【问题标题】:Java Synchronized Method and BlockJava 同步方法和块
【发布时间】:2012-10-22 23:08:16
【问题描述】:

我正在尝试更全面地了解 Java 中多个线程的同步。我了解使用 synchronized 关键字背后的高级思想,以及它如何在线程之间提供互斥。

唯一的问题是,即使您删除了使该主题比我认为需要的更混乱的同步关键字,我在网上和教科书中阅读的大多数示例仍然可以正常工作。

谁能给我一个具体的例子,说明什么时候不包括 synchronized 关键字会产生错误的结果?任何信息将不胜感激。

【问题讨论】:

  • 你看过Race Conditions吗?该页面上有一个很好的示例。
  • 我看了一下这个例子,但它有点抽象。我了解比赛条件背后的想法

标签: java concurrency synchronization synchronized concurrent-programming


【解决方案1】:

您通常可以通过增加迭代次数来触发竞争条件。这是一个简单的示例,它适用于 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 提供了增量、get-and-set 等的原子操作。

【讨论】:

    【解决方案2】:

    关于竞争条件的事情是,如果您没有进行适当的同步,它们就不会必然发生 - 实际上,它经常会正常工作 - 但一年后,在半夜,你的代码会因为一个完全无法预测的 bug 而崩溃,你无法重现,因为这个 bug 只是随机出现的。

    竞争条件之所以如此阴险,正是因为它们不会总是让您的程序崩溃,而且它们或多或少是随机触发的。

    【讨论】:

      猜你喜欢
      • 2022-12-10
      • 1970-01-01
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 1970-01-01
      相关资源
      最近更新 更多