因为它总是打印出'3'。不需要同步?我正在测试这个简单的事情,因为我在一个真正的多线程问题上遇到了麻烦,这不能很好地说明问题,因为它很大。这是一个展示情况的简化版本。
class Test {
public static int count = 0;
class CountThread extends Thread {
public void run()
{
count++;
}
}
public void add(){
CountThread a = new CountThread();
CountThread b = new CountThread();
CountThread c = new CountThread();
a.start();
b.start();
c.start();
try {
a.join();
b.join();
c.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
Test test = new Test();
System.out.println("START = " + Test.count);
test.add();
System.out.println("END: Account balance = " + Test.count);
}
答案 0 :(得分:4)
因为它总是打印出'3'。不需要同步?
这不是线程安全的,你只是运气好。如果运行1000次,或者在不同的体系结构上运行,您将看到不同的输出 - 即不是3。
我建议使用AtomicInteger
而不是静态字段++,而不是synchronized
。
public static AtomicInteger count = new AtomicInteger();
...
public void run() {
count.incrementAndGet();
}
...
答案 1 :(得分:2)
对我而言,像count++
一样快到足以完成,直到你为另一个类调用'run'。所以基本上它是顺序运行的
但是,如果这是一个真实的例子,并且两个不同的线程并行使用CountThread
,那么是的,你会遇到同步问题。
要验证这一点,您可以尝试在计数++之前和之后打印一些测试输出,然后在b.start()
完成之前,您将看到count++
是否正在调用a.start()
。 c.start()
也是如此。
请考虑使用AtomicInteger,这比尽可能同步更好 -
<强> incrementAndGet 强>
public final int incrementAndGet()
原子上将当前值增加1。
答案 2 :(得分:1)
此代码不是线程安全的:
public static int count = 0;
class CountThread extends Thread {
public void run()
{
count++;
}
}
您可以在一个系统上运行此代码一百万次,并且每次都可以通过。这并不意味着它是线程安全的。
考虑将count
中的值复制到多个处理器缓存的系统。在将某个缓存强制复制回主RAM之前,它们都可以独立更新。考虑++
不是原子操作。 count
的读写顺序可能会导致数据丢失。
实现此代码的正确方法(使用Java 5及更高版本):
public static java.util.concurrent.atomic.AtomicInteger count =
new java.util.concurrent.atomic.AtomicInteger();
class CountThread extends Thread {
public void run()
{
count.incrementAndGet();
}
}
答案 3 :(得分:0)
仅仅因为输出是正确的,它不是线程安全的。创建一个线程会导致操作系统方面的大量开销,之后只需要在单个时间段内完成该单行代码。它绝不是线程安全的,只是没有足够的潜在冲突来实际触发它。
答案 4 :(得分:0)
它不是线程安全的。
恰好可以通过缩短来获得显示问题的可衡量机会。考虑在run
中计数更高的数字(1000000?),以增加多个线程上2次操作重叠的可能性。
还要确保您的机器不是单核CPU ...
答案 5 :(得分:0)
要使类线程安全,请使count volatile
强制线程之间的内存屏障,或者使用 AtomicInteger ,或者像这样重写(我的偏好):
class CountThread extends Thread {
private static final Object lock = new Object();
public void run()
{
synchronized(lock) {
count++;
}
}
}