标签:string 完成 解决 回调 lis 错误 线程 type cut
花了三天时间试图做一个永远不能完成的任务。
需求:程序逻辑出现错误
@Autowired
private TwoHoursTaskThread twoHoursTaskThread;// 该实例是实现Runnable的一个单例
for(int i=0,l=list.size();i<l;i++)
{
ForfeitVO forfeitVO = list.get(i);
twoHoursTaskThread.setForfeitVO(forfeitVO);
Executors.newScheduledThreadPool(twoHoursTaskThread,10,TimeUnit.SECONDS);
}
理想的情况是:每次循环在一个线程中设置不同的ForfeitVO值,执行list.size()次 延时线程。
实际情况是:线程池只启用了一个线程。
错误原因:最开始是以为,这size个线程因为共享ForfeitVO变量,而线程池开启一个线程需要时间(还有延时开启的因素)造成线程开始执行的时候,用到的ForfeitVO变量已经不是和他在同一个循环里产生的ForfeitVO变量了。
后续的解决思路都是围绕着如何不共享变量展开的。最简单的方式就是 每次从spring 容器取出@Scope(value= prototype)的twoHoursTaskThread非单例,这样就不会共享实例变量了。可是这样就每次从spring容器那产生bean,肯定对内存有不少的消耗。
所以就想寻求 既能用单例(twoHoursTaskThread),又能避开共享变量。能想到的就是ThreadLocal,可是,如何能保证线程还没开始就已经初始化过这个=ThreadLocal变量呢?也就是如何向这个单实例传入不同参数呢?通过set方法或者初始化传参是不行的,只能通过最后一种方法,就是回调函数,可是这个回调函数如何判断哪个线程对应哪个ForfeitVO值呢,每个线程唯一不同的就是序号了,遂想就用这个i当做回调函数的参数吧,可是在for循环里怎么往线程里传参数呢,找到Thread(Runnable runnable,String name)初始化,这个name就用循环中的i,即:new Thread(twoHoursTaskThread,i).start()开启这个线程。可是这不是一样要新建对象吗,一样的浪费内存。抱着试试看的态度一试,结果居然发现只有一个线程跑起来。恍然大悟,一个实例只能开启一个线程,所以,想通过单例模式开多线程的路一开始就是个死路。
总结:问题定位不准惹的祸。
标签:string 完成 解决 回调 lis 错误 线程 type cut
原文地址:https://www.cnblogs.com/hezhiyuan/p/10445098.html