2017-02-10 87 views
2

我与一些并发的遗留代码挣扎,不知是否stopLatch和/或mode应该是volatile这是否并发遗留代码需要挥发性

public class MyClass { 

    private final ExecutorService executor = Executors.newSingleThreadExecutor(); 
    private MyModeEnum mode = MyModeEnum.NONE; 
    private CountDownLatch stopLatch; 

    public synchronized void start(final MyModeEnum mode) { 
     assert mode != null && mode != MyModeEnum.NONE; 
     if (isRunning()) { 
      // Throw an exception. 
     } 
     this.mode = mode; 
     stopLatch = new CountDownLatch(1); 
     executor.execute(() -> { 
      try { 
       // Pre and post operations not under control around stopLatch.await(). 
      } catch (final Exception e) { 
       stop(); 
       // Further exception handling. 
      } finally { 
       MyClass.this.mode = MyModeEnum.NONE; 
      } 
     }); 
    } 

    public synchronized void stop() { 
     if (!isRunning()) { 
      return; 
     } 
     stopLatch.countDown(); 
    } 

    public boolean isRunning() { 
     return mode != MyModeEnum.NONE; 
    } 

    public MyModeEnum getMode() { 
     return mode; 
    } 

} 

精心的解释非常赞赏。

编辑:我不能归结为一般问题/答案,如When exactly do you use the volatile keyword in Java?对这个特定的问题。

+1

同步块有当他们进入和退出所有线程同步,所以我不认为'volatile'是必要的。 – khelwood

+1

我会说只有'mode'需要'volatile',因为任何变化都需要对其他线程可见。注意:'assert'好像和'isRunning()'做的是一样的工作,我错了吗? – sp00m

+4

'isRunning() ''不'同步',所以'mode'应该是'volatile' ' –

回答

0

根据最upvoted评论:

  • Mick Mnemonic

    isRunning()不​​,所以mode应该volatile

  • Brian Goetz

    您对mode数据竞争。它是从同步块外部访问的。首选应该是同步isRunninggetMode;制作模式volatile是一个更高级的玩法。 (先走了,再飞。)