2013-04-24 66 views
0

在运行方法内使用同步块有意义吗?我认为它确实如此,只要我使用相关的锁,而不是包含此运行方法的Runnable实例。在stackoverflow上阅读类似问题的答案似乎证实了这一点。我试着写一些简单的代码进行测试和运行方法内同步块不从数据损坏预防:运行方法内的同步块

public class Test { 

    public Test() { 
     ExecutorService es = Executors.newCachedThreadPool(); 
     for (int i = 0; i < 1000; i++) { 
      es.execute(new Runnable() { 
       @Override 
       public void run() { 
        synchronized (lock) { 
         sum += 1; 
        } 
       } 
      }); 
     } 
     es.shutdown(); 
     while(!es.isTerminated()) { 
     } 
    } 
    private int sum = 0; 
    private final Object lock = new Object(); 

    public static void main(String[] args) { 
     Test t = new Test(); 
     System.out.println(t.sum); 
    } 
} 

为什么这个代码产生不正确的结果?这是因为同步块还是其他一些错误?我觉得我在这里错过了一些基本的东西。

+1

你正在做的一切正确,[它正常工作](http://ideone.com/XdaXCm)。 – dasblinkenlight 2013-04-24 01:01:31

+1

我想你可能会受到Java内存模型的影响。 – 2013-04-24 01:04:17

+0

你正在使用哪种JRE? – 2013-04-24 01:06:39

回答

1

您的执行者可能会遇到某种意外错误。如果发生这种情况,你不会知道它,因为你没有得到任何回报值来检查。

尝试切换到submit() instead execute()并存储Executor为您提供的Future实例列表。如果最后的总和小于1000,则迭代期货并得到()每一个。如果发生异常,您会看到特定的可运行任务发生了什么。

1

除了看起来不错的简单示例之外,您应该小心Runnables中的同步,以防止它们在一个Runnable等待某个资源仅由其他Runnable稍后在队列中释放时阻止彼此因为当前等待的Runnable必须先完成,所以永远不会启动。

虽然有足够的工作线程执行作业,但发生的可能性较小。