0

在 run 方法中使用同步块是否有意义?我认为确实如此,只要我使用的是相关锁,而不是包含此 run 方法的 Runnable 实例。阅读 stackoverflow 上类似问题的答案似乎证实了这一点。我尝试编写一些简单的代码来测试它,并且 run 方法中的同步块并不能防止数据损坏:

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);
    }
}

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

4

2 回答 2

1

除了看起来不错的简单示例之外,您应该小心 Runnables 中的同步,以防止它们在一个 Runnable 等待某个资源仅由队列中的另一个 Runnable 释放但尚未启动且永远不会相互阻塞时相互阻塞will 因为当前等待的 Runnable 必须首先完成。

但是,如果有足够的工作线程执行作业,这种情况就不太可能发生。

于 2013-04-24T07:52:38.683 回答
1

您的执行程序可能会遇到某种意外错误。如果发生这种情况,您将不会知道,因为您没有得到任何要检查的返回值。

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

于 2013-04-24T01:41:32.133 回答