精华帖 (0) :: 良好帖 (0) :: 新手帖 (14) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-04-18
public class TA extends Thread{ BusinessDAO bDAO; public TA(BusinessDAO daoArg){ bDAO = daoArg; } public run(){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } } } 请问我现在如何做到就是run()方法体内的代码在一个时刻内只有一个实例在运行?也就是说 bDAO.insert(dataList);这行代码在运新的时候,系统内只有一个dataList被传入,然后跟我的数据库系统已有的数据比较,然后得出结论,然后更新数据库状态。 这样做的原因是我现在的系统老是出现这样的情况,连续传2次dataList,按说第一次判断系统中没有这个datalist后,将这个dataList的值写入到数据库,那么第2次应该会判断出已经有了这个数据,但是实际情况不是,第二次判断仍然得出是没有的结论。而且在传入多次的情况下,结果都是一样。 这种结果从表面上看来就好像2次上传,第一次和第二次毫无关系一样,难道是2次是并发执行了? 请问这可能是什么原因造成的?那么我如何控制这种并发,保证我第一次判断,然后写入,然后才执行我第二次判断,第二次写入。 这个bug跟我的数据库的事务设置有关吗? 怎么解决这个问题? 还是要将我的程序设置成Singleton模式的? 怎么将我的程序设置成singleton模式的? 我的程序的实际架构是:Struts1.2+Spring2.0+iBatis3,以上的代码我抽象了一下。 线程TA是通过Spring的 org.springframework.core.task.TaskExecutor来调度的。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-04-18
这和单例无关,即使只有一个实例,那么如果不进行同步的话还是有线程并发。
问题的原因是线程并发的时候,第一线程插入DB表后还没有commit时,第二线程读取了这个表的纪录,当然就会出现你说的问题。 所以解决的方法是: 1、DAO方法执行开始就锁表,如果失败则等待直到超时; 2、Spring可以通过配置只生成一个实例,把BusinessDAO做成单例,然后注入, 但是下面的代码需要写到一个方法内并进行同步。 boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); 改成 bDAO.do(dataList) void do() { boolean b = findExist(dataList); if(!b){ insert(dataList); }else{ update(dataList); } } |
|
返回顶楼 | |
发表时间:2008-04-18
可不可以这样做?
将方法 public run(){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } 改成 public run(){ synchronized(this){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } } |
|
返回顶楼 | |
发表时间:2008-04-18
taikeqi 写道 可不可以这样做?
将方法 public run(){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } 改成 public run(){ synchronized(this){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } } run方法是属于某个线程的方法,不会涉及到多线程的并发。 发生问题的原因是有很多线程也就是很多run方法并发调用DAO或者说并发操作数据库, 所以解决问题的地方也是在DAO或者数据库。 向上面的修改方法我想是不起作用的 |
|
返回顶楼 | |
发表时间:2008-04-18
javazhujf 写道 taikeqi 写道 可不可以这样做?
将方法 public run(){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } 改成 public run(){ synchronized(this){ boolean b = bDAO.findExist(dataList); if(!b){ bDAO.insert(dataList); }else{ bDAO.update(dataList); } } run方法是属于某个线程的方法,不会涉及到多线程的并发。 发生问题的原因是有很多线程也就是很多run方法并发调用DAO或者说并发操作数据库, 所以解决问题的地方也是在DAO或者数据库。 向上面的修改方法我想是不起作用的 楼上的说错了吧? synchronized(this)就是用来防止多线程共享资源的问题,像上面那样加锁,我觉的可行,不过要加事务提交,不然insert的dataList还是不存在吧,并等事务提交好再让另一个线程执行应该不会错的 |
|
返回顶楼 | |
发表时间:2008-04-18
run方法是线程实例的方法,它只是在某个线程内执行。
|
|
返回顶楼 | |
发表时间:2008-04-18
是的但是run方法里面涉及的资源操作
run(){ 某个公共资源的操作, 比如你的存款余额, }, 既然继承了线程那这么说,这个类在生命周期内就不会只被调用一次,而且可能是不同的人同时调用,假如你的存款是1000,然后当扣了七七八八的费用电话,水电时候(假设扣了1000),你又去取了1000因为没有加锁,你钱也取了,费用也扣了那不是high死你了,那请问这是并发操作吧,我可以让它在两个线程里跑起来 你觉的不需要synchronized(this)起来吗 |
|
返回顶楼 | |
发表时间:2008-04-18
是我说错了,在run里同步没有问题,
不过按照封装的原则还是最好把同步操作封装到你说的“某个公共资源的操作”的方法里, 也就是楼主的DAO中。 |
|
返回顶楼 | |
发表时间:2008-04-18
是吗,我只是就是论事
楼主的主题如下: 主题:如何让在一个线程内DAO对象在一个时刻内只被调用一次? ,既然楼主要把dao封装到线程里,那在同一个时刻DAO对象要被只被调用一次当然要同步了,当然要不然new两个线程对象,同时执行的话那同一时刻不是有两个dao对象,进行对公共数据的操作了吗 当然你的想法是对的,一般我们只对调用共享资源的方法同步。 |
|
返回顶楼 | |
发表时间:2008-04-20
明明就是一个事务的问题,用的着这么麻烦吗,还是二楼的方法比较好,我觉得
|
|
返回顶楼 | |