我的课程安排如下:
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();}
}
答案 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访问)或通过锁管理。