为什么即使使用 AtomicInteger 来跟踪进度,此代码也不是线程安全的?
Why is this code not thread-safe even though an AtomicInteger is used to track progress?
我尝试制作一个 class 来扩展线程,它只接受一个字符串数组并交替打印前 2 个字符串,进行 10000 次迭代。我使用 AtomicInteger(计数器)跟踪要打印的索引,但输出有时会打印:
你好
你好
你好
w
你好
你好
等等
而不是在每次迭代中交替。为什么会这样,如果不将 'synchronized' 放入 运行 方法中,我该如何解决它?
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();
}
}
虽然号码是一个一个检索的,但方法的其余部分并未同步。所以有时可能会发生这种情况:
- t1: 从计数器中获取值 0
- t2: 从计数器中获取值 1
- t2:打印 w
- t1:打印 hello
一个快速解决方法是将整个 System.out 行放在一个 synchronized
块中,但这并不能保证线程轮流执行。它只是保证在下一个之前检索、递增和打印 echt 值。
如果您想让线程真正轮流执行,则必须实施某种锁定。但是如果你不想让线程互相等待,为什么要使用多线程?
编辑:另外,如果您打算以这种方式使用它,您可能应该让 MyThread 实现 Runnable 而不是扩展 Thread。有关更多信息,请参见 link:https://www.baeldung.com/java-runnable-vs-extending-thread(Solomon Slow 击败了我 :)
我尝试制作一个 class 来扩展线程,它只接受一个字符串数组并交替打印前 2 个字符串,进行 10000 次迭代。我使用 AtomicInteger(计数器)跟踪要打印的索引,但输出有时会打印: 你好 你好 你好 w 你好 你好 等等 而不是在每次迭代中交替。为什么会这样,如果不将 'synchronized' 放入 运行 方法中,我该如何解决它?
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();
}
}
虽然号码是一个一个检索的,但方法的其余部分并未同步。所以有时可能会发生这种情况:
- t1: 从计数器中获取值 0
- t2: 从计数器中获取值 1
- t2:打印 w
- t1:打印 hello
一个快速解决方法是将整个 System.out 行放在一个 synchronized
块中,但这并不能保证线程轮流执行。它只是保证在下一个之前检索、递增和打印 echt 值。
如果您想让线程真正轮流执行,则必须实施某种锁定。但是如果你不想让线程互相等待,为什么要使用多线程?
编辑:另外,如果您打算以这种方式使用它,您可能应该让 MyThread 实现 Runnable 而不是扩展 Thread。有关更多信息,请参见 link:https://www.baeldung.com/java-runnable-vs-extending-thread(Solomon Slow 击败了我 :)