我在多线程环境中尝试经典的int变量递增/递减。这是我的示例代码。
public class SyncIncDec {
public static void main(String[] args) {
SyncCounter count = new SyncCounter();
Thread incThread = new Thread(() -> {
count.increment();
});
Thread decThread = new Thread(() -> {
count.decrement();
});
Thread displayThread = new Thread(() -> {
System.out.println("Count value : " + count.getX());
});
incThread.start();
decThread.start();
displayThread.start();
try {
incThread.join();
} catch (InterruptedException e) {
// e.printStackTrace();
}
try {
decThread.join();
} catch (InterruptedException e) {
// e.printStackTrace();
}
try {
displayThread.join();
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
}
class SyncCounter {
private int x=0;
public SyncCounter() {
super();
}
public SyncCounter(int y) {
super();
x = y ;
}
synchronized int getX() {
return x;
}
void setX(int y) {
x = y ;
}
void increment() {
++x;
}
void decrement() {
--x;
}
}
虽然我已经为所有三个线程使用了join()方法,但我仍然得到不一致的结果。 这里没有加入意味着主线程要等到每个线程完成执行吗?我甚至尝试将synchronized同步添加到三个方法签名中的每一个;但我得到的结果不一致。
除了使用变量的原子版外,我还能怎样确保我总是得到0?
答案 0 :(得分:4)
仅在启动所有线程后才在三个线程上调用join()
。因此,您不能保证displayThread
变量引用的线程在递增和递减计数器的线程之后运行。
为确保在启动它们之后在这些线程上调用join()
:
incThread.start();
decThread.start();
incThread.join();
decThread.join();
displayThread.start();
它将阻塞当前线程,直到执行递增和递减,并且在join()
调用这些线程之后调用start()
的任何顺序。
答案 1 :(得分:2)
您的SyncCounter根本不是线程安全的。应该同步可变方法的递增和递减。现在几天实现这样一个类的正确方法将在atomic orations。 例如:
class SyncCounter {
private final AtomicInteger x;
public SyncCounter() {
this(0);
}
public SyncCounter(int x) {
this.x = new AtomicInteger(x);
}
int getX() {
return x.get();
}
void setX(int x) {
this.x.set(x);
}
int increment() {
return x.incrementAndGet();
}
int decrement() {
return x.decrementAndGet();
}
}
测试代码:
final Thread incThread = new Thread(() -> {
count.increment();
});
final Thread decThread = new Thread(() -> {
count.decrement();
});
Thread displayThread = new Thread(() -> {
incThread.join();
decThread.join();
System.out.println("Count value : " + count.getX());
});
答案 2 :(得分:0)
尽管我对所有三个线程都使用了join()方法,但结果仍然不一致。不是在这里加入就意味着主线程要等到每个线程都完成其执行之后?
您的代码中存在2个问题。
在您的SyncCounter
类中,仅getX()
方法被同步。因为您有3个线程共享该类的相同实例,所以读取或更新共享字段的任何方法都必须为synchronized
。这意味着increment()
和decrement()
方法也必须是synchronized
。如@Victor所述,用SyncCounter
代替AtomicInteger
是一个简单的解决方案,尽管我怀疑您的锻炼需要手工完成。
...
synchronized int increment() {
...
synchronized int decrement() {
在线程模型中,递增和递减线程与显示线程之间存在竞争条件。仅仅因为您在其他线程之后启动显示线程并不意味着它最后运行。显示线程可能首先完成,在这种情况下,根据比赛条件,它将显示0或显示-1或1。此处最简单的解决方案是让主线程与增量线程和减量线程连接,然后 then 打印输出结果。
// start the inc and dec threads running in the background
incThread.start();
decThread.start();
// wait for inc thread to finish
incThread.join();
// wait for dec thread to finish
decThread.join();
// now we can print out the value of the counter
System.out.println("Count value : " + count.getX());
如果必须具有显示线程,则应在之后启动 像@davidxxx这样的增量和减量线程的联接 推荐。
// start the inc and dec threads running in the background
incThread.start();
decThread.start();
// wait for inc thread to finish
incThread.join();
// wait for dec thread to finish
decThread.join();
// now start the display thread now that the increment/decrement is done
displayThread.start();
// wait for the display thread to finish
displayThread.join();