【问题标题】:Why is this code not thread-safe even though an AtomicInteger is used to track progress?为什么即使使用 AtomicInteger 来跟踪进度,这段代码也不是线程安全的?
【发布时间】:2019-04-26 13:02:57
【问题描述】:

我尝试创建一个扩展线程的类,它只需要一个字符串数组并交替打印前 2 个字符串,以进行 10000 次迭代。我使用 AtomicInteger (计数器)跟踪要打印的索引,但是输出有时会打印: 你好 你好 你好 w 你好 你好 等等 而不是在每次迭代时交替。为什么会这样?如果不将“同步”放在 run 方法中,我该如何解决?

public class MyThreadDelegate implements Runnable {

  List<String> words;
  AtomicInteger counter = new AtomicInteger(0);

  public MyThread(List<String> words) {
    this.words = words;
  }

  @Override
  public void run() {
    for (int i = 0; i < 10000; i++) {
      System.out.println(words.get(counter.getAndIncrement()%2) + counter.get());
    }
  }

  public static void main(String[] args) {

    MyThreadDelegate myThreadDelegate = new MyThreadDelegate(Arrays.asList("hello", "w"));

    Thread t1 = new Thread(MyThreadDelegate);
    Thread t2 = new Thread(MyThreadDelegate);

    t1.start();
    t2.start();
  }
}

【问题讨论】:

  • 拜托!将MyThread extends Thread 更改为MyThreadDelegate implements Runnable。您的myThread 对象不是线程,因为您从不调用myThread.start()。您的t1t2 对象是线程,每个都使用您的myThread 对象作为它们的Runnable delegate
  • P.S.,这个练习教你一些关于如何同步线程的知识,但是在任何实际程序中,如果线程不花费至少 一些 时间独立运行,不同步的任务,那么这几乎违背了首先使用线程的整个目的。

标签: multithreading concurrency atomicinteger


【解决方案1】:

虽然数字被一一检索,但该方法的其余部分并未同步。所以有时可能会发生这种情况:

  • t1:从计数器获取值 0
  • t2:从计数器获取值 1
  • t2:打印 w
  • t1:打印你好

快速解决方法是将整个 System.out 行放在 synchronized 块中,但这不能保证线程轮流运行。它只是保证 echt 值在下一个值之前被检索、递增和打印。

如果您想让线程真正轮流运行,则必须实现某种锁定。但是如果你不想让线程互相等待,你为什么要使用多个线程呢?

编辑:另外,如果您打算以这种方式使用它,您可能应该让 MyThread 实现 Runnable 而不是扩展 Thread。有关更多信息,请参阅此链接:https://www.baeldung.com/java-runnable-vs-extending-thread(Solomon Slow 击败了我:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2014-06-22
    • 2011-05-18
    相关资源
    最近更新 更多