Lock的Condition使用

2024-05-03 18:08
文章标签 使用 lock condition

本文主要是介绍Lock的Condition使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 Lock是java 1.5中引入的线程同步工具,它主要用于多线程下共享资源的控制。

Condition 本质是一个接口,它包含如下方法

// 让线程进入等通知待状态 
void await() throws InterruptedException; 
void awaitUninterruptibly();
//让线程进入等待通知状态,超时结束等待状态,并抛出异常  
long awaitNanos(long nanosTimeout) throws InterruptedException; 
boolean await(long time, TimeUnit unit) throws InterruptedException; 
boolean awaitUntil(Date deadline) throws InterruptedException; //将条件队列中的一个线程,从等待通知状态转换为等待锁状态 
void signal(); //将条件队列中的所有线程,从等待通知阻塞状态转换为等待锁阻塞状态
void signalAll();

           一个Condition实例的内部实际上维护了一个队列,队列中的节点表示由于(某些条件不满足而)线程自身调用await方法阻塞的线程。Condition接口中有两个重要的方法,即 await方法和 signal方法。线程调用这个方法之前该线程必须已经获取了Condition实例所依附的锁。这样的原因有两个,(1)对于await方法,它内部会执行释放锁的操作,所以使用前必须获取锁。(2)对于signal方法,是为了避免多个线程同时调用同一个Condition实例的singal方法时引起的(队列)出列竞争。下面是这两个方法的执行流程。

          await方法:

                            1. 入列到条件队列(注意这里不是等待锁的队列

                            2. 释放锁

                            3. 阻塞自身线程

                             ------------被唤醒后执行-------------

                            4. 尝试去获取锁(执行到这里时线程已不在条件队列中,而是位于等待(锁的)队列中,参见signal方法)

                                4.1 成功,从await方法中返回,执行线程后面的代码

                                4.2 失败,阻塞自己(等待前一个节点释放锁时将它唤醒)

         注意:await方法时自身线程调用的,线程在await方法中阻塞,并没有从await方法中返回,当唤醒后继续执行await方法中后面的代码(也就是获取锁的代码)。可以看出await方法释放了锁,又尝试获得锁。当获取锁不成功的时候当前线程仍然会阻塞到await方法中,等待前一个节点释放锁后再将其唤醒。


         signal方法:

                           1. 将条件队列的队首节点取出,放入等待锁队列的队尾

                           2. 唤醒该节点对应的线程

         注意:signal是由其它线程调用


Lock和Condition的使用例程

public class ConditionCommunication {
/**
* @param args
*/
public static void main(String[] args) {

final Business business = new Business();
new Thread(new Runnable() {
        @Override
      public void run() {
          for(int i=1;i<=50;i++){
              business.sub(i);
                 }
}}).start();
             for(int i=1;i<=50;i++){
              business.main(i);
                 }
     }


         static class Business {
              Lock lock = new ReentrantLock();
              Condition condition = lock.newCondition();
              private boolean bShouldSub = true;
             public  void sub(int i){
                          lock.lock();
                     try{
                       while(!bShouldSub){
                   try {
                     condition.await();
                        } catch (Exception e) {
                    e.printStackTrace();
                    }
            }
                 for(int j=1;j<=10;j++){
                    System.out.println("sub thread sequence of " + j + ",loop of " + i);
         }
             bShouldSub = false;
            condition.signal();
            }finally{
              lock.unlock();
        }
    }
 
           public  void main(int i){
                  lock.lock();
                   try{
                       while(bShouldSub){
try {
                                    condition.await();
                                       } catch (Exception e) {
                                                 e.printStackTrace();
                                                                           }
  }
                                      for(int j=1;j<=100;j++){
                                   System.out.println("main thread sequence of " + j + ",loop of " + i);
                                        }
                             bShouldSub = true;
                              condition.signal();
                       }finally{
                             lock.unlock();
                            }
               }

        }
}

Lock与synchronized的区别

          1. Lock的加锁和解锁都是由java代码配合native方法(调用操作系统的相关方法)实现的,而synchronize的加锁和解锁的过程是由JVM管理的

          2. 当一个线程使用synchronize获取锁时,若锁被其他线程占用着,那么当前只能被阻塞,直到成功获取锁。而Lock则提供超时锁和可中断等更加灵活的方式,在未能获取锁的     条件下提供一种退出的机制。

          3. 一个锁内部可以有多个Condition实例,即有多路条件队列,而synchronize只有一路条件队列;同样Condition也提供灵活的阻塞方式,在未获得通知之前可以通过中断线程以    及设置等待时限等方式退出条件队列。

         4. synchronize对线程的同步仅提供独占模式,而Lock即可以提供独占模式,也可以提供共享模式


这篇关于Lock的Condition使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/957333

相关文章

Java Stream流与使用操作指南

《JavaStream流与使用操作指南》Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库,本文给大家介绍JavaStream流与使用... 目录一、什么是stream流二、创建stream流1.单列集合创建stream流2.双列集合创建str

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa