zoukankan      html  css  js  c++  java
  • Java高并发synchronized讲解生产者消费者

    问题描述

    题目:两个线程操作一个变量,实现两个线程对同一个资源一个进行加1操作,另外一个进行减1操作,且需要交替实现,变量的初始值为0。即两个线程对同一个资源进行加一减一交替操作。话不多说,开干
    首先我们先定义操作的资源,并且定义方法。

    首先定义资源类

    //资源类
    class Resource {
        private int number = 0;
    
        public synchronized void up() throws InterruptedException {
            //1.判断
            if(number != 0) {
                this.wait();
            }
            //2.干活
            number++;
            System.out.println(Thread.currentThread().getName() + "	" + number);
            this.notifyAll();
        }
    
        public synchronized void down() throws InterruptedException {
            if(number == 0) {
                this.wait();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "	" + number);
            this.notifyAll();
        }
    }

    接着我们写我们的两个线程

    public class ThreadWaitNotifyDemo {
        public static void main(String[] args) {
            Resource resource = new Resource();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.up();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }, "A").start();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.down();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "B").start();      
        }
    }

    结果如下图

    这里我们通过Lambda表达式来通过匿名内部类来创建线程并启动,可以看到一个线程up方法,另外一个线程进行down方法,
    首先比如线程A先判断是否为0,不为0,那么此时进行加1操作,同一时刻的B线程此时判断的是number等于0,那么就进行等待操作,这个时候A线程加完了,然后通过notifyAll()方法来唤醒其他的线程,所以就完成了减的操作,这里for0~10是为了保证能够交替进行10次。

    wait 方法和notify方法是Thread的方法吗?

    这里扩展一个知识点,wait 方法和notify方法是Thread的方法吗?
    答案:错错错 。
    查看API我们可以见到这两个方法属于Object的方法,wait 和 notify 必须要配合synchronized 关键字使用。

     

    这就完了吗??

    需求变更

    不不不,此时需求改动了!这个时候项目经理过来说,小王,我不要两个线程操作了,我要四个线程同时操作,两个进行相加,两个进行相减,还是交替到时必须是0,1相互的交替。
    这个时候心想,简单呀,我再多加两个线程!
    于是,多加了两个线程。
    代码如下,Resource不变。

    public class ThreadWaitNotifyDemo {
        public static void main(String[] args) {
            Resource resource = new Resource();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.up();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }, "A").start();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.down();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "B").start();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.up();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "C").start();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        resource.down();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "D").start();
        }
    }

    和之前的一样,多加了两个线程,一个进行加,一个进行减操作。
    然后run一下,结果如下图:

     这里我们就看到,有的为3了,这是什么情况???

    分析:举个例子,A,C线程是进行加操作,B,D是进行减操作,此时如果是0,那么B,和D线程是被wait了的对吧,A和C因为up方法被加了锁,所以只有一个方法进行加,如果此时A进行完操作,然后再notifyall,那么此时C线程也会进行up操作,

    因为C线程在if(number!=0){this.wait();}这里被唤醒后,继续进行其他的操作了,且在A执行完加1操作和后没有继续判断number的情况,同理B,D线程也是如此,所以就会出现上图的情况!
    那么这种情况怎么解决呢??

    解决方案

    因为我们是没有重新进行判断,那么,我们让其重新进行判断就是了!
    修改资源类代码如下:

    class Resource {
        private int number = 0;
    
        public synchronized void up() throws InterruptedException {
            //1.判断
            while (number != 0) {
                this.wait();
            }
            //2.干活
            number++;
            System.out.println(Thread.currentThread().getName() + "	" + number);
            this.notifyAll();
        }
    
        public synchronized void down() throws InterruptedException {
            while (number == 0) {
                this.wait();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "	" + number);
            this.notifyAll();
        }
    }

    四个线程的操作资源的代码不变,结果如下:

  • 相关阅读:
    预定义规则 取范围数据
    oracle table 数组的赋值方法
    java 缓存读写
    webpack
    vscode setting
    webpack babel
    共享你的vscode配置
    github API很丰富
    tips
    todo
  • 原文地址:https://www.cnblogs.com/yanl55555/p/13540277.html
Copyright © 2011-2022 走看看