我有这段代码:
import java.util.concurrent.atomic.AtomicLong;
interface Counter {
public void increment();
public void decrement();
public int value();
}
class SynchronizedCounter implements Counter {
private int c = 0;
@Override
public synchronized void increment() {
c++;
}
@Override
public synchronized void decrement() {
c--;
}
@Override
public synchronized int value() {
return c;
}
}
class UnsynchronizedCounter implements Counter {
private int c = 0;
@Override
public void increment() {
c++;
}
@Override
public void decrement() {
c--;
}
@Override
public int value() {
return c;
}
}
public class TestProjectApp {
public static void main(String[] args) {
AtomicLong unsynchronizedErrors = new AtomicLong();
AtomicLong synchronizedErrors = new AtomicLong();
for (int i = 0; i < 1000; i++) {
Counter c = new UnsynchronizedCounter();
(new Thread(() -> {
c.increment();
})).start();
(new Thread(() -> {
if (c.value() != 1) {
unsynchronizedErrors.incrementAndGet();
}
})).start();
}
for (int i = 0; i < 1000; i++) {
Counter c = new SynchronizedCounter();
(new Thread(() -> {
c.increment();
})).start();
(new Thread(() -> {
if (c.value() != 1) {
synchronizedErrors.incrementAndGet();
}
})).start();
}
System.out.println("Unsynchronized errors: " + unsynchronizedErrors);
System.out.println("Synchronized errors: " + synchronizedErrors);
}
}
执行我的程序的结果是:
Unsynchronized errors: 83
Synchronized errors: 26
我理解为什么会出现非同步错误,但我不明白为什么会出现同步错误。
我的假设是在第二个循环中,增加同步错误数的线程必须等到使用SynchronizedCounter :: increment()方法的线程。我的想法有什么不对?
似乎没有必要使这些方法同步,但在第二个线程中使用Thread :: join()方法就足够了。但我仍然不明白为什么它没有奏效。
答案 0 :(得分:2)
你的假设是错误的。 synchronized
保证您的方法的执行不会交错,并且它们将具有 排序。您希望线程以特定顺序运行,但您不以任何方式强制执行该命令。
在第二个循环中,您希望线程按照创建线程的顺序到达同步方法的执行。但是在循环体中可能会发生什么
Counter c = new SynchronizedCounter();
(new Thread(() -> {
c.increment();
})).start();
(new Thread(() -> {
if (c.value() != 1) {
synchronizedErrors.incrementAndGet();
}
})).start();
您创建的{strong>第二 Thread
(synchronizedErrors
检查程序)是在第一个之前运行的join
(执行递增的那个) )。您将此归类为错误,但没有发生错误。
解决此问题的最佳方法是 if(condition){
some.changeLabel1();
}else{
some.changeLabel2();
}
在查询计数器状态之前进行递增/递减的所有线程。