即使使用AtomicInteger跟踪进度,为什么此代码也不是线程安全的?

时间:2019-04-26 13:02:58

标签: multithreading concurrency atomicinteger

我尝试制作一个扩展线程的类,该类仅采用字符串数组并交替输出前2个字符串以进行10000次迭代。我使用AtomicInteger(计数器)来跟踪要打印的索引,但是输出有时会打印以下内容: 你好 你好 你好 w 你好 你好 等等 而不是每次迭代都交替进行。为什么会这样?如何在不将“ synchronized”放入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();
  }
}

1 个答案:

答案 0 :(得分:0)

虽然数字被一个接一个地检索,但其余方法未同步。因此有时可能会发生这种情况:

  • 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击败了我:)