Java ExecutorService:我应该先使用lock来使用execute吗?

时间:2013-04-17 11:08:30

标签: java multithreading thread-safety

我的课程安排如下:

public class MyClass {

   ExecutorService pool;

   public MyClass(){
     pool = ... //inited by a class that implements ExecutorService
   }

   public final void submit(Runnable run){
        pool.execute(run);
   }
}

方法submit线程是否安全,或者我应该使用基于Lock的系统? E.g。

   ReentrantLock look  = new ReentrantLock();

   public final void submit(Runnable run){
        lock.lock();
        try{ pool.execute(run); } finally{lock.unlock();}
   }

2 个答案:

答案 0 :(得分:8)

在致电ExecutorService#submit时,您不需要锁定。

  

内存一致性效果:在向ExecutorService提交Runnable或Callable任务之前的一个线程中的操作发生在该任务执行的任何操作之前,而该操作又发生在通过Future.get()检索结果之前

或致电Executor#execute时:

  

内存一致性效果:在将Runnable对象提交给Executor之前,线程中的操作发生在执行开始之前,可能是在另一个线程中。

答案 1 :(得分:1)

这取决于您ExecutorService的访问方式或MyClass的创建方式。如果在单个线程中创建了MyClass的实例,并且还在单个线程中创建了#pool ivar,则此类是线程安全的,并且您对#pool的使用是线程安全的。

但是,如果您的MyClass可以跨多个线程存在(例如首先通过单例,共享工厂或共享列表访问 - 即不是new MyClass()),那么它不是线程安全的。这是因为多个线程可以访问您的Myclass实例及其单个#pool ivar。可以同时调用提交但多个线程,因此Myclass实例或pool的状态可能会受到影响。在这种情况下,您的MyClass#submit应该通过锁同步或管理。由于这是一种娇小的方法,我建议只是同步#submit

同样,如果在此线程中创建了MyClass实例,但在此线程中#pool未创建为新pool = new AnExecutorPoolType(...);,那么此类将不再是线程安全的。再次从多个线程可用的另一个源(如上所述)访问。如果是这种情况,则存在多个线程访问使其处于不一致状态的风险。在这种情况下,pool#execute方法应该同步(或通过同步块保护ivar访问)或通过锁管理。