【发布时间】:2019-11-29 08:38:25
【问题描述】:
在这段代码中,我使用了 10 个线程来更新 AtomicInteger 变量。我希望 Counter.getInstance().holder.n 的最终结果是 1000000,但它会打印出像 991591 这样的随机数。 我的代码有什么问题?
public class Test {
public static void main(String[] args) {
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
list.add(new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
Counter.getInstance().holder.n.incrementAndGet();
}
}
});
}
for (Thread thread : list) {
thread.start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Counter.getInstance().holder.n);
}
}
class Counter {
private static Counter counter;
Holder holder = new Holder();
public static Counter getInstance() {
if (counter == null) {
counter = new Counter();
}
return counter;
}
class Holder {
AtomicInteger n = new AtomicInteger(0);
}
}
【问题讨论】:
-
您的 Counter 单例不是线程安全的,睡眠 10 秒并不能保证所有线程都已完成运行。为您的原子整数使用一个简单的静态变量,并在所有线程上调用 thread.join()(在一个额外的循环中)以等待它们的终止。
-
你能解释一下为什么单例不是线程安全的吗?以及如何使其线程安全?
-
因为两个线程可以同时调用getInstance(),都看到counter为null,都创建了一个新的Counter。而且由于没有任何同步,即使一个线程已经将静态计数器设置为非空值,另一个线程也不能保证看到它。使其线程安全:只需使用
static final AtomicInteger N = new AtomicInteger(0)
标签: java multithreading concurrency thread-safety atomicinteger