2013-04-17 57 views
3

我有一个类安排如下:Java ExecutorService:我应该在执行之前放置一个锁吗?

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为基础的系统?例如。

ReentrantLock look = new ReentrantLock(); 

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

回答

8

调用ExecutorService#submit时,没有你不需要锁。

内存一致性效果:在提交一个Runnable或可调用任务的一个ExecutorService的前一个线程动作发生-之前由该任务,这反过来又发生-之前结果经由未来检索所采取的任何行动。得到()。

或主叫Executor#execute时:

内存一致性效果:提交Runnable对象到一个执行器之前操作在一个线程发生-之前其执行开始,也许在另一个线程。

+0

谢谢!答案是完整的和详尽的! –

1

这取决于你如何为ExecutorService访问或如何建立您的MyClass。如果在单个线程中创建MyClass的实例,并且在一个线程中也创建了#pool ivar,那么此类是线程安全的,并且您使用#pool是线程安全的。但是,如果MyClass可以存在于多个线程中(例如首先通过单例,共享工厂或共享列表访问 - 即不是new MyClass()),那么它不是线程安全的。这是因为多个线程可以访问您的Myclass实例及其单个#pool伊娃。调用提交可以一次完成,但可以同时执行多个线程,因此您的Myclass实例或pool的状态可能会受到影响。在这种情况下,您的MyClass#submit应该被锁定同步或管理。由于这是一个小巧的方法,我建议只是同步#submit

同样,如果在此线程创建您的MyClass实例,但#pool没有新的创造,在这个线程(pool = new AnExecutorPoolType(...);那么这个类就再不会是线程安全的。池可以再次从另一个源(如上)访问的在多线程中是可用的,如果是这种情况,则存在多线程访问时处于不一致状态的风险,在这种情况下,应该同步(或通过守护ivar访问的同步模块)或管理通过锁

+0

其实,MyClass是一个枚举设计用于使用池作为一个单身人士。 –

+0

我在这里重新阅读我的答案时有些惊慌,认为“看起来不正确”。但是,我将要离开它,因为我认为我所做的是...... ExecutorService可能是线程安全的(虽然这实际上取决于实现[尽管java impls是“happen-before”]),但是您的实现的提交可能不是线程安全的。在到达'ExecutorService'之前,你的'Myclass#submit'中可能会出现另一个线程,并导致命令不符合你的预期。所以,你的班级可能需要警惕这一点。 – wmorrison365

+0

另请参见[ThreadPoolExecutor线程安全吗?](http://stackoverflow.com/questions/1702386/is-threadpoolexecutor-thread-safe)。 – wmorrison365

相关问题