JUC编程中的Condition类

img

Condition中的await和signal

在JUC编程中使用await替换了Object类中的wait,signal替换Object中的notify。(作用大致相同)

示例 结合传统多线程实现生产者和消费者问题对比学习

package com.cn.JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample01 {
    public static void main(String[] args) {

        Data2 data = new Data2();
        //创建一个生产者
        new Thread(()->{
            for (int i = 0; i < 15; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        //创建一个消费者
        new Thread(()->{
            for (int i = 0; i < 15; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();


        //创建一个生产者 A
        new Thread(()->{
            for (int i = 0; i < 15; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        //创建一个消费者 D
        new Thread(()->{
            for (int i = 0; i < 15; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}


//这是一个缓冲类,生产和消费之间的仓库
class Data2 {
    //这是仓库的资源,生产者生产资源,消费者消费资源
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //    +1,利用可重入锁加锁
    public void increment() throws InterruptedException {
        //首先查看仓库中的资源(num),如果资源不为0,就利用 wait 方法等待消费,释放锁
        lock.lock();
        try {
        // 使用 if 存在虚假唤醒,所以使用while
            while (num != 0) {
                condition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "=>" + num);
        //通知其他线程 +1 执行完毕
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    // -1操作
    public void decrement() throws InterruptedException {
        lock.lock();
        //首先查看仓库中的资源(num),如果资源为0,就利用 wait 方法等待生产,释放锁
        try {
            while (num == 0) {
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "=>" + num);
            //通知其他线程 -1 执行完毕
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

我们发现运行的结果和传统方法实现生产者和消费者并没有多大区别,那么我们为什么还要使用Condition呢?

使用Condition的好处

使用Condition可以精准的通知和唤醒某个线程!

示例:A通知B,B通知C,C通知A

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample02 {
    public static void main(String[] args) {
        Data3 data3 = new Data3();

        new Thread(()->{
            for (int i = 0; i < 3; i++) {
                data3.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 3; i++) {
                data3.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 3; i++) {
                data3.printC();
            }
        },"C").start();
    }
}

class Data3{
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int num = 1; // 1A 2B 3C

    public void printA(){
        lock.lock();
        try {
//            业务代码 判断 -> 执行 -> 通知
            while (num != 1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=> A ");
            num = 2;
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB(){
        lock.lock();
        try {
//            业务代码 判断 -> 执行 -> 通知
            while (num != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=> B ");
            num = 3;
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC(){
        lock.lock();
        try {
//            业务代码 判断 -> 执行 -> 通知
            while (num != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=> C ");
            num = 1;
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

结果 我们发现是按照通知顺序执行的。这就是conditon的好处。

A=> A 
B=> B 
C=> C 
A=> A 
B=> B 
C=> C 
A=> A 
B=> B 
C=> C 

参考教程:狂神学java

posted @ 2021-04-20 18:01  懒鑫人  阅读(231)  评论(0)    收藏  举报