notify和notifyAll的区别,notify死锁问题

具体讲解参照博客区别
下面补充一个例子,来说明,使用notify会产生死锁,但是使用notifyAll不会。

原题为lleetcode 1195

大体意思是:四个线程,调用同一个对象的四个不同方法,然后实现线程的同步。

在这里使用了synchornized和state来实现这个题目。
下面分析一种情况说明notify会产生死锁,而notifyAll会。

修改完state = 0后,使用notify激活了应该执行state = 3的线程A。
然后,线程state = 0, 调用了wait方法,锁死了自己。
此时,锁队列上,挂了四个线程,虽然此时的锁已经释放了,但是没有外部的干预,四个线程都没有回到竞争队列上面的时候。
这就出现了有锁,但是无法执行的状态。
但是这并不是操作系统意义上面的死锁。因为不满足死锁的四个状态。

package leetcode;

import java.util.function.IntConsumer;


/*
*
*   这里是一个错误的同步
* */
public class FizzBuzz3 extends FizzBuzz{
    // 使用synchornize + state的方式来实现
    private int state = 0;     // 0 : 数字, 1 :fizz, 2:buzz, 3
    private Object obj = new Object();
    private int n;

    public FizzBuzz3(int n) {
        super(n);
        this.n = n;
    }
    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        for (int i = 3; i <= n; i += 3) {
            if (i % 5 == 0) continue;
            synchronized (obj) {
                while (state != 1) {
                    obj.wait();
                }
                printFizz.run();
                state = 0;
                obj.notifyAll();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        for (int i = 5; i <= n; i += 5) {
            if (i % 3 == 0) continue;       // 如果不行,就不该状态,否则最后一个可能输出不了
            synchronized (obj) {
                while (state != 2) {
                    obj.wait();
                }
                printBuzz.run();
                state = 0;
                obj.notifyAll();       // 可能会死锁,如果都wait就死锁了。
            }
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        for (int i = 15; i <= n; i += 15) {     // 只要等于3,就可以直接输出了
            synchronized (obj) {
                while (state != 3) {
                    obj.wait();
                }
//                System.out.println("\nstate = " + state + " i = " + i);
                printFizzBuzz.run();
                state = 0;          // 只有输出才有资格改,否则自己也能竞争
                obj.notifyAll();
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            synchronized (obj) {
                while (state != 0) {
                    obj.wait();
                }
                if (i % 3 != 0 && i % 5 != 0) {
                    printNumber.accept(i);
                } else {
                    if (i % 3 == 0 && i % 5 == 0) {
                        state = 3;
                    } else if (i % 5 == 0) {
                        state = 2;
                    } else state = 1;
                }
//                System.out.println(" state = " + state);
                obj.notifyAll();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        String[] className = {"leetcode.FizzBuzz3", "20"};
        FuzzBuzzMain.main(className);
    }
}

你可能感兴趣的:(后台,java,开发语言)