Java多线程同步操作中为什么要用 while 而不是 if

比方说在多生产、多消费的场景

这里直接举例来说明吧

class Buf{
    private final int MAX = 5;
    private final ArrayList<Integer> list = new ArrayList<>();
    synchronized void put(int v) throws InterruptedException {
        if (list.size() == MAX) {
            wait();
        }
        System.out.println("put v = "+v + ", thread = "+ Thread.currentThread().getName());
        list.add(v);
        notifyAll();
    }

    synchronized int get() throws InterruptedException {
        // 为什么多线程同步的时候 要用while而不是if
        //A线程和B线程在执行 get 方法的时候,由于list 的 size 为 0, 所以A和B线程都执行wait方法阻塞住并且释放了锁。
        //C 线程执行put操作是,调用 notifyAll() 方法唤醒A和B线程,假设是A线程先获得锁,那么A remove 后,现在 list 的大小又为 0 了
        // 此时线程A调用 notifyAll 方法来唤醒B线程,那么B线程获得锁之后,会直接调用 remove 方法,此时 list 的大小为0,所以报 IndexOutOfBoundsException

        // 解决方法就是将 if 改为 while 就好了,因为 是while的话, 此时线程A调用 notifyAll 方法来唤醒B线程,那么B线程获得锁之后 会执行 while 语句,判断 size == 0,执行 wait 方法
        if (list.size() == 0) {
            System.out.println("get 执行 wait" + ", thread = "+ Thread.currentThread().getName());
            wait();
        }
        int v = list.remove(0);
        System.out.println("get v = " + v + ", thread = "+ Thread.currentThread().getName());
        notifyAll();
        return v;
    }
}

具体的解释见代码中的注释吧!!!

你可能感兴趣的:(Java-多线程)