JUC练习代码-Synchronized实现生产者消费者问题

生产者消费者问题,用Synchronized关键字解决方法如下:
两个线程操作同一个对象,一个进行+1操作,一个进行-1操作。
本代码仅用于练习操作,不要直接在生产环境执行。

public class JUCTest01 {
    public static void main(String[] args) throws InterruptedException {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

    }
}

//判断是否等待,业务,干完活通知
class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        if (number != 0) {
            //等待
            this.wait();
        }
        number++;

        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName() + "执行了+1" + ";number=" + number);
        this.notifyAll();


    }

    public synchronized void decrement() throws InterruptedException {
        if (number == 0) {
            //等待
            this.wait();
        }
        number--;

        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName() + "执行了-1" + ";number=" + number);
        this.notifyAll();

    }
}

代码执行结果:
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0

上面样例,仅存在AB两个对变量进行操作,如果我们将代码修改下,增加一CD等线程一起进行操作。
则会打印出number=2,3,负数等其他异常情况。

上述代码中我们用了if去进行判断其实是有问题的。

jdk文档中也注明,因为存在虚假唤醒,wait方法最好放在while循环中。
JUC练习代码-Synchronized实现生产者消费者问题_第1张图片
我们将上述方法if改为while条件判断下。

public class JUCTest01 {
    public static void main(String[] args) throws InterruptedException {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }
}

//判断是否等待,业务,干完活通知
class Data {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            //等待
            this.wait();
        }
        number++;

        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName() + "执行了+1" + ";number=" + number);
        this.notifyAll();


    }

    public synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            //等待
            this.wait();
        }
        number--;

        //通知其他线程,我+1完毕了
        System.out.println(Thread.currentThread().getName() + "执行了-1" + ";number=" + number);
        this.notifyAll();

    }
}

再次执行打印结果,则可以正常输出01。

你可能感兴趣的:(高并发多线程(Java提升篇))