在使用lock 和 ExecutorService 时需要注意的问题

来源:互联网 发布:魔兽世界有mac版本吗 编辑:程序博客网 时间:2024/05/16 06:33

     在最近的项目中,有这样一个需求,有一个计算量比较大的功能,在一个用户触发一次计算任务之后,在这个任务结束之前不能让该用户再次触发计算任务,但是又不能影响到别的用户使用这个计算任务。先不讨论这样的需求的合理性,单从技术角度来看一下这个问题。

     在项目中,另外一位同事也做了一个相似的功能,他的实现思路是用数据库来记录每个用户的执行状态,当用户触发这个功能的时候去判断执行状态从而决定是否进行下一步,如果可以执行就修改执行状态,当其他线程读到这个状态的时候就可以判断是否可以执行。这样的设计思路可能是跟他的数据库结构刚好提供了这样的字段有很大关系,但是我的数据库中不可能因为这样一个功能来单独的增加一个字段,所以就不能采用这个方式了。而且,后来我仔细想了一下,这样的实现方式是不太可靠的,比如说,当一个线程读到的执行状态是可以执行的,那么它去修改数据库,但是这时候如果连接池的连接用完了,需要阻塞等待,而这时候又有一个线程来读取执行状态,发现是可以执行的,这样就会有两个线程可以执行,而且数据库连接阻塞的时间越长,可以执行的线程数就越多,显然是不符合要求的。

    我的做法是,在程序中使用锁,并使用一个ConcurrentHashMap来保存每个用户的执行状态:

   

    我的实现思路是,在线程开始执行时,加锁,修改这个用户的状态值,然后ExecutorService 执行任务,在全部任务执行完成之后,再修改用户执行状态,每次开始执行的时候去判断用户是否可以继续执行。这样应该是没有什么问题了,但是多线程和锁可能会出现意想不到的事情,还有待验证。

    在使用程序自旋等待任务执行的过程中出了一个错误,先把正确的代码贴出来:

  

   由于程序中需要根据任务量的大小来决定线程池的大小,在判断线程池中任务是否完全执行完成的时候,误用了另一个线程池的isTerminated()方法,结果就是我的程序直接死循环了。把问题修改完之后又查了一下资料,发现ExecutorService如果没有执行线程任务,那么它的isTerminated()方法就永远不会返回true,就好像经常说的“没有开始,就没有结束”。还有一个方法叫做isShutdown(),它在ExecutorService执行完shutdown()之后就会返回true,而isTerminated()是在线程池中的所有任务执行完成之后才返回true,使用时需要注意区别。

       

0 0