Java多线Condition条件变量正确使用方法详解
前言
本篇文章的代码示例已放到 github 上,Git地址为:advance(记录每一个学习过程),大家在项目介绍的引用目录里面即可找到对应文章的一个代码路径。
大家有任何问题,欢迎大家在评论区留言,我会在看到后一一进行回复。
背景
在介绍 Condtion 的使用场景之前,我们先来考虑这样的场景:
当我们在执行某个方法之前,我们获得了这个方法的锁,但是在执行过程中我们发现某个条件不满足,想让方法暂停一会儿,等条件满足后再让这个方法继续执行。
针对上面的问题,我们可以利用Object.wait()和notify()写出下面这样的代码:
public synchronized void doSomething(){ //执行方法 if(条件不满足){ //线程等待 Object.wait(); } //条件此时满足,对象被唤醒,继续执行方法 }
但是,由于Object.wait()和notify()过于底层,并且无法区分是由于等待超时后唤醒还是被其他线程唤醒的问题,引入在JDK1.5后引入了java.util.concurrent.locks.Condition接口。
使用场景
Condition接口作为Object.wait()/notify()的替代品,当我们给某个方法加锁后,发现某个条件不满足,想让方法暂停一会儿,等条件满足后再让这个方法继续执行。这种时候,我们就可以使用Condition接口。
常用方法
创建一个condition实例
为了让这个锁更方便获得,实例代码里面我将这个锁设为静态的
//定义一个锁 public static final Lock reentrantLock = new ReentrantLock(); //定义属于这个锁的条件变量 public static final Condition condition = reentrantLock.newCondition();
线程等待
void await() throws InterruptedException;
线程非阻塞等待
boolean await(long time, TimeUnit unit)
唤醒某个线程
condition.signal();
唤醒所有线程
condition.signalAll();
使用示例
定义一个全局的标志位
public class GlobalSymbol { /** * 定义全局标志位 */ public static AtomicBoolean globalFlag = new AtomicBoolean(false); }
主线程
public class Main { //定义一个锁 public static final Lock reentrantLock = new ReentrantLock(); //定义属于这个锁的条件变量 public static final Condition condition = reentrantLock.newCondition(); public static void main(String[] args) { //先启动一下线程 Thread thread = new Thread(new OtherThread()); thread.start(); //先加锁 reentrantLock.lock(); try { System.out.println("线程加锁成功,正在执行相关代码"); while (!GlobalSymbol.globalFlag.get()){ System.out.println("现在条件还不满足,先等待"); condition.await(); } System.out.println("线程被唤醒,执行后续代码"); } catch (Exception e){ System.out.println("加锁解锁逻辑出现异常"); } finally { //在finally中释放锁 reentrantLock.unlock(); } System.out.println("程序结束"); } }
子线程(用于唤醒主线程)
public class OtherThread implements Runnable{ @Override public void run() { try { for (int i = 10; i > 0; i--){ System.out.println("标志位将在" + i + "秒后置为true"); TimeUnit.SECONDS.sleep(1); } GlobalSymbol.globalFlag.set(true); //对被阻塞的线程进行唤醒(必须获得对应的锁后,才能执行唤醒的操作) Main.reentrantLock.lock(); Main.condition.signalAll(); Main.reentrantLock.unlock(); } catch (Exception e){ System.out.println("线程执行失败"); } } }
运行结果
注意事项
- 加锁操作lock()一般放在try语句的外面,且紧接着try语句;
- 解锁操作unlock()一般放在finally语句中,避免报错后造成锁泄漏;
- 调用signalAll()进行唤醒时,一定要持有对应的锁才能调用该方法,直接调用该方法会抛异常。
以上就是Java多线condition条件变量正确使用 方法详解的详细内容,更多关于Java多线程condition条件变量的资料请关注脚本之家其它相关文章!
相关文章
详解Spring Security 捕获 filter 层面异常返回我们自定义的内容
Spring 的异常会转发到 BasicErrorController 中进行异常写入,然后才会返回客户端。所以,我们可以在 BasicErrorController 对 filter异常进行捕获并处理,下面通过本文给大家介绍Spring Security 捕获 filter 层面异常,返回我们自定义的内容,感兴趣的朋友一起看看吧2022-05-05SpringBoot整合MyBatis逆向工程及 MyBatis通用Mapper实例详解
这篇文章主要介绍了SpringBoot整合MyBatis逆向工程及 MyBatis通用Mapper实例详解 ,需要的朋友可以参考下2017-09-09Springmvc DispatcherServlet原理及用法解析
这篇文章主要介绍了Springmvc DispatcherServlet原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-09-09
最新评论