在多线程里面,为什么推荐使用notifyAll而不是notify

2023-10-29  本文已影响0人  深夜小码农

在多线程里面,为什么推荐使用notifyAll而不是notify?


结论:notify容易造成死锁

1、无论使用notify或者notifyAll,都是随机唤醒线程

2、notify是随机唤醒一个线程去执行,noifyAll是唤醒所有线程,然后去抢占锁,去执行

怎么产生死锁现象:

P – 生产者 调用 putproduct C – 消费者 调用 consumer。

  1. P2 调用product,发现满了,在wait里面等了。

  2. P2 调用product,发现满了,在wait里面等了。

  3. P2 调用product,发现满了,在wait里面等了。

  4. C1 想来拿,C2,C3 就在 consumer里面等着。

  5. C1 开始执行,移除remove,然后调用 notify 然后退出。

  1. 这时候我们发现 P2、C2、C3 都在等着锁,最终 P2 拿到了锁,放一个 1,notify,然后退出。

  2. P2 这个时候唤醒了P3,P3发现队列是满的,没办法,只能等它变为空。 8. 这时候没有别的调用了,那么现在这三个线程(P3, C2,C3)就全部变成 suspend 了,也就是死锁了。

代码示例
public class Thread03{

    private Buffer mbuffer = new Buffer();
    // private List<Object> list = new ArrayList<>();

    public void product(){
        synchronized (this) {
            while (mbuffer.isFull()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            mbuffer.add();
            notify();
        }

    }

    public void consumer(){
        synchronized (this) {
            while (mbuffer.isEmpty()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            mbuffer.remove();
            notify();
        }

    }

    private class Buffer {
        private static final int MAX_CAPACITY = 1;
        private List innerList = new ArrayList<>(MAX_CAPACITY);

        void add() {
            if (isFull()) {
                throw new IndexOutOfBoundsException();
            } else {
                innerList.add(new Object());
            }
            System.out.println(Thread.currentThread().toString() + " add");

        }

        void remove() {
            if (isEmpty()) {
                throw new IndexOutOfBoundsException();
            } else {
                innerList.remove(MAX_CAPACITY - 1);
            }
            System.out.println(Thread.currentThread().toString() + " remove");
        }

        boolean isEmpty() {
            return innerList.isEmpty();
        }

        boolean isFull() {
            return innerList.size() == MAX_CAPACITY;
        }
    }

    public static void main(String[] args) {
        Thread03 thread03 = new Thread03();
        Runnable product = new Runnable() {
            int count = 4;

            @Override
            public void run() {
                while (count-- > 0) {
                    thread03.product();
                }

            }
        };

        Runnable consumer = new Runnable(){
            @Override
            public void run() {
                int count = 4;
                while (count-- >0){
                    thread03.consumer();
                }            }
        };

        for (int i = 0; i < 2; i++) {
            new Thread(product).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(consumer).start();
        }
    }

}
上一篇 下一篇

猜你喜欢

热点阅读