Java同步方法和块



我试图更充分地了解Java中多个线程的同步。我了解使用同步关键字背后的高级思想,以及它如何在线程之间提供相互排除。

唯一的事情是,即使您删除了同步的关键字,我在线阅读的大多数示例仍然可以正常工作,这使该主题比我认为需要的更令人困惑。

谁能为我提供一个具体示例,即不包括同步关键字会产生错误的结果吗?任何信息都将不胜感激。

您通常可以通过增加迭代次数来触发竞赛条件。这是一个简单的示例,可与100和1,000迭代一起使用,但在10,000迭代(有时)的情况下(至少在我的四核框上)。

public class Race
{
    static final int ITERATIONS = 10000;
    static int counter;
    public static void main(String[] args) throws InterruptedException {
        System.out.println("start");
        Thread first = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < ITERATIONS; i++) {
                    counter++;
                }
            }
        });
        Thread second = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < ITERATIONS; i++) {
                    counter++;
                }
            }
        });
        first.start();
        second.start();
        first.join();
        second.join();
        System.out.println("Counter " + counter + " should be " + (2 * ITERATIONS));
    }
}
>>> Counter 12325 should be 20000

此示例失败了,因为对counter的访问未正确同步。它可以通过两种方式失败,可能两者都在同一运行中:

  • 一个线程没有看到另一个线程增加了计数器,因为它看不到新值。
  • 一个线程在读取当前值并编写新值的另一个线程之间递增计数器。这是因为增量和减少操作员不是原子。

这个简单程序的修复程序将是使用AtomicInteger。使用volatile是由于增量问题而不足,但是AtomicInteger提供了用于增量,观察到的原子操作,等等。

关于种族条件的事情是,如果您不进行适当的同步,则不一定会发生很好 - 但是一年后,在深夜,您的代码将崩溃,因为该错误仅随机出现。

种族条件是如此阴险,恰恰是因为它们不会总是使您的程序崩溃,并且它们或多或少触发。

相关内容

  • 没有找到相关文章

最新更新