Condition等待唤醒

前言

在Java中,每个对象都可以调用 Object 的 wait/notify 方法来实现等待/通知机制。而 Condition 接口也提供了类似的方法,也能实现等待唤醒,Condition需要在ReentrantLock下使用,也就是需要上锁和释放锁,否则也会报java.lang.IllegalMonitorStateException

Condition使用

Condition方法

Condition提供await()、signal()、signalAll()方法,其中,await()是让线程等待,signal()是唤醒一个线程,signalAll()是唤醒全部线程,当前线程调用condition.await()方法后,会释放 lock 然后加入到等待队列,直到被 signal/signalAll 方法唤醒

Condition等待唤醒使用

1、await()等待唤醒

ini 复制代码
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionTest {

    public static void main(String[] args) {
        final ReentrantLock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread thread1 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                System.out.println(name + " <==进入条件队列等待");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(name + ":线程被唤醒");
        }, "aa");

        thread1.start();

        Thread thread2 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                Thread.sleep(5000);
                System.out.println(name + ":开始唤醒线程");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            condition.signalAll();
            lock.unlock();
            System.out.println(name + ":唤醒结束");
        }, "通知线程");

        thread2.start();
    }
}

输出结果为

signal()只能唤醒一个线程

ini 复制代码
package cn.com.ut.july.wait;

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

public class ConditionTest {

    public static void main(String[] args) {
        final ReentrantLock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread thread1 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                System.out.println(name + " <==进入条件队列等待");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(name + ":线程被唤醒");
        }, "aa");

        thread1.start();

        Thread thread3 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                System.out.println(name + " <==进入条件队列等待");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(name + ":线程被唤醒");
        }, "aa1");

        thread3.start();

        Thread thread2 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                Thread.sleep(5000);
                System.out.println(name + ":开始唤醒线程");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            condition.signal();
            lock.unlock();
            System.out.println(name + ":唤醒结束");
        }, "通知线程");

        thread2.start();
    }
}

输出结果为

signalAll()唤醒全部线程

ini 复制代码
package cn.com.ut.july.wait;

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

public class ConditionTest {

    public static void main(String[] args) {
        final ReentrantLock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread thread1 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                System.out.println(name + " <==进入条件队列等待");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(name + ":线程被唤醒");
        }, "aa");

        thread1.start();

        Thread thread3 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                System.out.println(name + " <==进入条件队列等待");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
            System.out.println(name + ":线程被唤醒");
        }, "aa1");

        thread3.start();

        Thread thread2 = new Thread(() -> {
            String name = Thread.currentThread().getName();

            lock.lock();
            try {
                Thread.sleep(5000);
                System.out.println(name + ":开始唤醒线程");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            condition.signalAll();
            lock.unlock();
            System.out.println(name + ":唤醒结束");
        }, "通知线程");

        thread2.start();
    }
}

输出结果为

Condition实现三个线程顺序输出

scss 复制代码
package cn.com.ut.july.wait;

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

public class ConditionDemo {

    public static void main(String[] args) throws InterruptedException {

        ReentrantLock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Condition condition3 = lock.newCondition();

        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(500);
                    System.out.println("A");
                    lock.lock();
                    condition2.signal();
                    condition1.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        }).start();
        Thread.sleep(100);
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(500);
                    System.out.println("B");
                    lock.lock();
                    condition3.signal();
                    condition2.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        }).start();
        Thread.sleep(100);
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(500);
                    System.out.println("C");
                    lock.lock();
                    condition1.signal();
                    condition3.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lock.unlock();
                }
            }
        }).start();

    }

}

输出结果为

使用Thread.sleep()是为了保证先start()的线程先启动,以及不输出那么快

总结

Condition的await()和signal()基于Lock,相比于基于Object的wait()和notify()方法,它提供更加灵活的等待通知的机制,并且是基于AQS队列形式,但是在开发过程中,根据自己喜好选择

相关推荐
.Bryce.5 小时前
你了解 Blackboard(黑板系统)吗?听说过基于黑板系统实现的智能体吗?
java·网络·gpt·php·agent·codex·黑板系统
猿究院_夏燊12 小时前
Spring Bean 生命周期
java·后端·spring
Wang's Blog13 小时前
Java 项目实战: 交友项目:登录链路回顾与今日任务地图
java·开发语言·状态模式·交友
信誓旦旦的程序猿13 小时前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
砚底藏山河13 小时前
python量化:行情数据回溯
java·开发语言·python·金融·maven
Jlzn888813 小时前
华东电芯分选通道数怎么配才不堵线
java·人工智能·架构·自动化·制造
香吧香14 小时前
GRPC连接机制---长连接分析
java·网络与传输协议
我是人✓14 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
Wang's Blog14 小时前
Java 项目实战: 交友项目 - 阿里云 OSS 入门案例:从创建 Bucket 到上传拿到可访问 URL
java·阿里云·交友
裕晟资质规划15 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全