这个例子中是否存在竞争条件?如果是这样,怎么可以避免呢?

tre*_*dro 7 java multithreading synchronization synchronized race-condition

我正在查看一些通知/等待示例,并遇到了这个.我理解同步块本质上定义了一个关键部分,但是这不是一个竞争条件吗?Nothing指定首先输入哪个同步块.

public class ThreadA {
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();

        synchronized(b){
            try{
                System.out.println("Waiting for b to complete...");
                b.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }

        System.out.println("Total is: " + b.total);
        }
    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            notify();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

每个网站的输出:

等待b完成......

总计是:4950

Nat*_*hes 5

是的,它不能保证首先执行哪个线程.线程b可以在主线程开始等待之前进行通知.

除此之外,线程可以在没有得到通知的情况下从等待返回,因此在进入等待之前设置标志并检查它在技术上是不够的.你可以把它重写成类似的东西

public class ThreadA {
    public static void main(String[] args) throws InterruptedException {
        ThreadB b = new ThreadB();
        b.start();

        synchronized(b){
            while (!b.isDone()) {
                System.out.println("Waiting for b to complete...");
                b.wait();
            }
            System.out.println("Total is: " + b.total);
        }
    }
}

class ThreadB extends Thread {
    int total;
    private boolean done = false;

    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            done = true;
            notify();
        }
    }

    public boolean isDone() {return done;}
}
Run Code Online (Sandbox Code Playgroud)

这样主线程将等到b完成计算,无论谁先启动.

顺便说一下,API文档建议您不要在线程上进行同步.JDK在线程上同步以实现Thread#join.终止的线程发送notifyAll,它接收到的任何东西都会收到.如果你从一个获得锁定的线程中调用notify或notifyAll,那么加入它的东西可能会提前返回.这里的一个副作用是,如果您删除通知代码以相同的方式工作.