关于 java线程的 锁池、等待池(二)

2023-11-03 15:58
文章标签 java 线程 等待 锁池

本文主要是介绍关于 java线程的 锁池、等待池(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

围绕着:「等待池中被 "唤醒"notifyAll() 的线程一定会进入锁池吗?」

接着上篇转载的博客:https://blog.csdn.net/ScorpC/article/details/90296146

自己又继续深入研究了这个问题,查阅了java虚拟机经典书籍《Inside the Java Virtual Machine(第2版)》,瞬间懂!

不仅感叹,经典就是经典,能成为经典一定是有原因的!

也告诫自己,尤其是基础的东西,遇到问题,最好优先自己亲自查阅书籍、阅读源码、官方开发文档等

共勉!

以下内容总结自此书的:第20章 线程同步

 

 

可以在语言级支持多线程是java语言的一大优势,这种支持主要集中在同步上,或调解多个线程的活动和共享数据。Java所使用的同步机制是监视器。本章讲述了监视器,展示了java虚拟机使用它们的方式,还描述了指令集在数据的锁定和解锁方面是如何支持监视器的。

1. java中的监视器支持两种线程:互斥和协作

   java虚拟机通过对象锁来实现互斥;

   协作则是通过Object类的wait()和notify()方法来实现;

2. java虚拟机所使用的这种监视器被称作“等待并唤醒”监视器(有时也被称作“发信号并继续”监视器);

 

在这种监视器中,一个已经持有监视器的线程,可以通过执行一个等待命令,暂停自身的执行。当线程执行了等待命令后,它就会释放监视器,并进入一个等待区,这个线程会在那里一直持续暂停状态,直到一段时间后,这个监视器中的其他线程执行了唤醒命令。当一个线程执行了唤醒命令之后,它会继续持有监视器,直到它主动释放监视器,如执行了一个等待命令或者执行完监视区域。当执行唤醒的线程释放了监视器后等待线程苏醒,并重新获得监视器。

 

java虚拟机中的监视器模型如上图所示,将监视器分成了三个区域:

         中间的大方框包括一个单独的线程,是监视器的持有者;

         左边的小方框是入口;

         右边是另一个小方框是等待区;

         活动线程用深灰色圆画出;

         暂停的线程用浅灰色画出;

 

3. 上图也显示了线程与监视器交互所必须“通过”的几道门;

 

当一个线程到达监视区域的开始出时,它会通过最左边的1号门进入监视器,发现自己身处在那个叫入口区的方框中;

 

如果该没有任何线程正持有监视器,也没有其他线程正在入口区中等待,这个线程就会立刻通过下一道门:2号门,并持有监视器;

作为这个监视器的持有者,它将继续执行监视区域中的代码;

 

或者也可能出现另一种情况,已经有另一个线程正持有监视器,这个新到达的线程就必须在入口区域等待,很可能那里已经有一些线程在等待了,这个线程会被阻塞,所以不能执行监视区域中的代码;

 

如果一个监视器的持有者在它释放监视器前没有执行唤醒命令(同时在此之前也没有任何等待线程被唤醒并等待苏醒),那么位于入口区中的那些线程将会竞争获得监视器。如果上一个持有者执行了唤醒命令,入口区中的线程就不得不与一个或多个等待区中的线程来竞争。而如果是等待区中的某个线程赢了,它会通过4号门退出等待区并重新获得监视器。注意,一个线程只有通过3号门和4号门才能进入或退出等待区。一个线程只有在它正持有监视器时才能执行等待命令,而且它只能通过再次成为监视器的持有者才能离开等待区;

 

在java虚拟机中,线程在执行等待命令时可以随意指定一个暂停时间。如果一个线程指定了暂停时间,而且在暂停时间截止之前没有其他线程执行唤醒命令。这个等待线程会从虚拟机得到一个自动唤醒的命令。也就是说,在暂停时间到了以后,即使没有来自其他线程的唤醒命令,它也会自动苏醒。

 

Java虚拟机提供了两种唤醒命令:”notify”和”notify all“。notify命令随意从等待区中选择一个线程并将其标志为 "可能苏醒" ,而notify all 命令会将等待区中的所有线程都标志成 "可能苏醒"

 

Java虚拟机如何从等待区以及入口区选择下一个线程来执行,在很大程度上取决于java虚拟机的设计者;

 

总之,实现可以任意自由选择哪一个线程;

 

程序员必须不依赖任何特定的有关优先级的算法或者安排,至少在编写平台无关的java程序时应该这样;

 

比如说,因为不知道notify命令将会导致等待区中的哪一个线程苏醒,只有当绝对确认只会有一个线程在等待区中挂起的时候,才应该使用notify(相对notify all)而言。只要存在同时有多个线程在等待区中被挂起的可能性,就应该使用notify all。

 

4.对象锁

在前面的章节中提到过,java虚拟机的一些运行时数据区会被所有的线程共享,其他的数据是各个线程私有的;

 

因为方法区是被所有线程共享的,java程序需要为两种多线程访问数据进行协调:

        保存在堆中的实例变量;

        保存在方法区中的类变量;

程序不需要协调保存在java栈中的局部变量,因为java栈中的数据是属于拥有该栈的线程私有的;

 

在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。对于对象来说,相关联的监视器保护对象的实例变量。对于类来说,监视器保护类的类变量。如果一个对象没有实例变量,或者一个类没有类变量,相关联的监视器就什么都不监视。

 

类锁实际上用对象锁实现:java虚拟机在加载一个class文件的时候,它会创建一个java.lang.Class类的实例。当锁住一个类的时候,实际上锁住的是那个类的Class对象。

 

一个线程可以允许多次对同一个对象上锁。对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁。没有被锁的对象的计数器是0.但一个线程第一次获得锁的时候,计数器跳到1. 线程每加锁一次,计数器就加1。(只有已经拥有了这个对象的锁的线程才能对该对象再次加锁,在它释放锁之前,其他的线程不能对这个对象加锁)每当线程释放锁一次,计数器就减1.当计数器跳到0的时候,锁就完全释放了,其他的线程才可以使用它。

 

注意:java程序员不需要自己动手加锁,对象锁是在java虚拟机内部使用的。在java程序中,你只需要编写同步语句或者同步方法就可以标志一个监视区域。当java虚拟机运行你的程序的时候,每一次进入一个监视区域的时候,它每次都会自动锁上对象或者类。

 

 

这篇关于关于 java线程的 锁池、等待池(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

idea maven编译报错Java heap space的解决方法

《ideamaven编译报错Javaheapspace的解决方法》这篇文章主要为大家详细介绍了ideamaven编译报错Javaheapspace的相关解决方法,文中的示例代码讲解详细,感兴趣的... 目录1.增加 Maven 编译的堆内存2. 增加 IntelliJ IDEA 的堆内存3. 优化 Mave

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

springboot filter实现请求响应全链路拦截

《springbootfilter实现请求响应全链路拦截》这篇文章主要为大家详细介绍了SpringBoot如何结合Filter同时拦截请求和响应,从而实现​​日志采集自动化,感兴趣的小伙伴可以跟随小... 目录一、为什么你需要这个过滤器?​​​二、核心实现:一个Filter搞定双向数据流​​​​三、完整代码

SpringBoot利用@Validated注解优雅实现参数校验

《SpringBoot利用@Validated注解优雅实现参数校验》在开发Web应用时,用户输入的合法性校验是保障系统稳定性的基础,​SpringBoot的@Validated注解提供了一种更优雅的解... 目录​一、为什么需要参数校验二、Validated 的核心用法​1. 基础校验2. php分组校验3

Java Predicate接口定义详解

《JavaPredicate接口定义详解》Predicate是Java中的一个函数式接口,它代表一个判断逻辑,接收一个输入参数,返回一个布尔值,:本文主要介绍JavaPredicate接口的定义... 目录Java Predicate接口Java lamda表达式 Predicate<T>、BiFuncti

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与