• Java并发编程虚假唤醒问题(生产者和消费者关系)


    何为虚假唤醒:

    当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功;
    比如买货:如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了,但是只能一个人买,所以其他人都是假唤醒,获取不到对象的锁;

    避免虚假唤醒:

    Synchronized版,生产者和消费者问题

    package com.jia.pc;
    
    public class A {
    
        public static void main(String[] args) {
    
            Data data = new Data();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"A").start();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"B").start();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"C").start();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"D").start();
        }
    }
    
    // 等待,业务,通知
    class Data{
    
        private int number = 0;
    
        // +1
        public synchronized void increment() throws InterruptedException {
            while (number != 0){
                // 等待
                this.wait();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "->" + number);
            // 通知其他线程,我+1完毕
            this.notifyAll();
        }
    
        // -1
        public synchronized void decrement() throws InterruptedException {
            while (number == 0){
                // 等待
                this.wait();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "->" + number);
            // 通知其他线程,我-1完毕
            this.notifyAll();
        }
    }

    运行结果:

    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    A->1
    B->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    C->1
    D->0
    
    Process finished with exit code 0

    虚假幻想是如何产生的?

      把 while (number != 0) {}

      换成 if (number == 0) {}

      就会出现虚假唤醒。官方文档有标注;

    为什么if判断会出现虚假唤醒?

      1. 因为if只会执行一次,执行完会接着向下执行if()外边的

      2. 而while不会,直到条件满足才会向下执行while()外边的

    JUC版,生产者和消费者问题

    使用 Condition 代码实现:

    package com.jia.pc;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class C {
    
        public static void main(String[] args) {
    
            Data3 data = new Data3();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    data.printA();
                }
            },"A").start();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    data.printB();
                }
            },"B").start();
    
            new Thread(()->{
                for (int i = 0; i < 10 ; i++) {
                    data.printC();
                }
            },"C").start();
        }
    }
    
    // 资源类
    class Data3{
    
        private Lock lock = new ReentrantLock();
    
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();
    
        private int number = 1;
    
        public void printA(){
            lock.lock();
            try {
               while (number != 1){
                   //等待
                   conditionA.await();
               }
                System.out.println(Thread.currentThread().getName()+"->"+"AAAAA");
                //唤醒执行的线程 B
                number = 2;
                conditionB.signal();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public void printB(){
            lock.lock();
            try {
                while (number != 2){
                    //等待
                    conditionB.await();
                }
                System.out.println(Thread.currentThread().getName()+"->"+"BBBBB");
                //唤醒 C
                number = 3;
                conditionC.signal();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public void printC(){
            lock.lock();
            try {
                while (number != 3){
                    //等待
                    conditionC.await();
                }
                System.out.println(Thread.currentThread().getName()+"->"+"CCCCC");
                //唤醒 A
                number = 1;
                conditionA.signal();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

    Condition:它可以精准的通知和唤醒线程;

     
  • 相关阅读:
    特征选择常用算法综述
    干货:结合Scikit-learn介绍几种常用的特征选择方法
    机器学习中,有哪些特征选择的工程方法?
    牛逼的博客地址
    Discover Feature Engineering, How to Engineer Features and How to Get Good at It
    机器学习中的Bias(偏差),Error(误差),和Variance(方差)有什么区别和联系?
    机器学习中使用「正则化来防止过拟合」到底是一个什么原理?为什么正则化项就可以防止过拟合?
    Libsvm和Liblinear的使用经验谈
    Python 由list转为dictionary
    使用 numpy.random.choice随机采样
  • 原文地址:https://www.cnblogs.com/luckyjcx/p/12638105.html
Copyright © 2020-2023  润新知