JAVA语言规范-线程和锁章节之同步、等待和通知
JAVA语言规范:线程和锁 1 同步
java编程语言提供了线程间通信的多种机制。这些方法中最基本的是同步化,此方法是使用监视器实现的。JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视器。一次仅有一个线程可能在监视器上持有锁。尝试锁住该监视器的任何其他线程被阻塞,直到它们可以再该监视器上获得一个锁。线程 t可以多次锁住特别的监视器;每个解锁将一个加锁操作的作用反转来了。
synchronized语句计算了一个对象的引用;然后它尝试在该对象的监视器上执行加锁操作,并不进一步继续,直到锁操作已经成功完成。在加锁操作被执行完后,会执行synchronized语句体。如果语句体的执行没有完成(正常或突然)。那么将在相同的监视器上自动执行相同的解锁操作。
JAVA编程语言没有防止,也没有要求检查死锁条件。线程在多个对象上(直接或间接)持有锁的程序,应该使用传统技术来避免死锁,创建不会死锁的高级加锁原语(如果有必要的话)。其他机制(比如读写java.util.concurrent 包中的 volatile 变量和类)提供了一些同步的其他方法。
2 等待集合 和 通知
JAVA中的每个对象,都有一个关联的监视器,也会有一个关联的等待集合。等待集合是一个线程的集合。
当对象第一次被创建时,它的等待集合为空,增加或移除该集合中的线程,这样的简单操作都是原子性的。等待集合受到以下方法的操纵: Object.wait, Object.notify, and Object.notifyAll.。
等待集合的操作也受到线程中断状态的的影响,还有Thread类中那些可以进行中断线程方法的影响。此外在Thread类中的sleep和join的方法,它们能够获得等待集合和通知的动作。
2.1等待(Wait)
等待操作由wait()方法的执行引起,或者也可以由限定时间长度的wait()方法触发。
调用方法wait(long millisecs)或者函数wait(long millisecs, int nanosecs) ,当调用的参数均为0时,这样的调用等同于wait()。
如果线程在没有抛出InterruptedException 的情况下返回,那么线程就从wait 正常返回。
令线程t是在对象m上执行等待方法的线程,并令n是t在m上加锁操作的编号,这些操作已经不被解锁操作匹配。下面的操作之一发生:
如果n是0(也就是,线程t已经没有占用目标m的锁)则抛出IllegalMonitorStateException 异常。 如果这是一个定时等待,并且十亿分之一秒参数不在0-999999,或者毫秒参数是负的,那么就会抛出IllegalArgumentException 的异常。 如果线程t被中断,那就抛出InterruptedException,并将t的中断状态设置为假。
否则,下面的序列发生:
1、线程t被添加到对象m的等待集合中,并在m上执行n个解锁操作。
2、线程t没有执行任何的进一步指令,直到它已经从m的等待集合中删除。由于下面的操作的任何之一,该程序可能从等待集合中删除,并在后面的某个时间继续。
在等待等待集合中删除而选择的t的m上正在执行的notify操作。 在m上正被执行的notifyAll操作。 在t上执行的interrupt操作。 如果这是一个定时等待,则为m的等待集合删除的内部操作,该集合至少在millisecs毫秒加nanosecs十亿分之一秒消逝后发生(从写操作开始)。 根据实现的内部操作。实现被允许(尽管不鼓励)执行“伪造的唤醒”——以便从等待集合中删除中删除线程,从而能够在没有显式指令这样做的情况下再继续。注意这个装备成了在循环内使用wait的JAVA编码实践的必要条件,这些循环只有在线程等待持有的某个逻辑条件时才终止。
每个线程必须通过可能导致它从等待集合中删除的时间确定顺序。顺序不一定与其他的排序一直,但线程表现得像以那个循环发生的那些事件一样。
例如,如果线程t在m的等待队列中,然后t的中断和m的通知发生,那么在这些事件上必须有一个顺序。如果中断被认为首先发生,那么t将最终通过抛出 InterruptedException来从wait中中返回,而且中的等待集合的某个其他线程(如果在通知的时候存在的话)必须接收通知。如果通知被认为是首先发生的,那么t将最终正常地wait返回,且中断仍然挂起。
线程t在m上执行n个加锁操作。 如果由于中断线程t在步骤2中从m的等待集合中删除了,那么t的中断状态就被设置为假,并且等待方法抛出InterruptedException。
2.2 通知(notify)
通知操作在调用方法notify和notifyAll 调用之后发生。令线程t是执行对象m上的这些方法的任一方法的线程,并令n是t在m上的加锁操作的数量,这些操作没有被解锁操作匹配。下面操作之一发生了。
如果n是0,则抛出IllegalMonitorStateException。情形是这样的:线程t已经没有占有目标m的锁。 如果n大于0,并且这是一个notify操作,那么如果m的等待集合不是空的,则是m的当前等待集合的一个成员的线程u被选择,并从等待集合中删除(不保证在等待集合中选定哪个线程)。从等待集合中进行该删除让u在等待操作中得以继续。但注意,继续之后的u的加锁操作不能成功,直到t完全解锁m的监视器后的某个时间。 如果n大于0,并且这是一个notifyAll操作,那么所有的线程就从m的等待集合中删除并继续,但请注意。它们当中仅有的一个将一次锁住wait的继续期间需要的监视器 2.3 中断
中断操作在调用方法Thread.interrupt及定义来依次调用它的方法(比如ThreadGroup.interrupt)之后发生。对于某个线程u,令t是调用u.interrupt的线程,其中t和u可能是相同的。此操作导致u的中断状态被设置为真。
另外,如果存在着等待集合包含u的某个对象m,那么u就从m的等待集合中删除。这使得u能够在等待操作中继续,在该操作的情况中,此等待将在重新加锁m的监视器后抛出InterruptedException。
调用Thread.isInterrupted可以确定线程的中断状态。静态方法Thread.interrupted有线程调用来观察和清除自己的中断状态。
2.4 等待、通知和中断的交互
上面的规范允许我们确定于等待、通知和中断有关的几个属性。如果在等待时,线程同时是通知和中断的,它就可能是下面之一:
从wait正常返回,尽管仍然有挂起中断(在其他工作中,对Thread.interrupted的调用将返回真)。 通过抛出InterruptedException从wait处返回。
线程不可以重置它的中断状态,并从wait的调用中正常返回。
同样,通知不能由于中断而丢失。假定线程的集合s在对象m的等待集合中,并且另一个线程在m上执行notify,那么有下面之一发生:
至少s中有一个线程从wait处正常返回,或者 s中的所有线程必须通过抛出InterruptedException退出wait。
注意,如果线程通过notify被中断和唤醒,并且线程通过抛出InterruptedException从wait返回,那么等待集合中的某个线程必须被通知到。
JAVA语言规范-线程和锁章节之同步、等待和通知的更多相关文章
- java 语言规范 java language specifications
在线地址: https://docs.oracle.com/javase/specs/ java语言规范下载: 链接:http://pan.baidu.com/s/1miEpJwk 密码:f89v j ...
- JAVA语言规范和API网址
Java语言规范: http://docs.oracle.com/javase/specs/ Java API: http://docs.oracle.com/javase/8/docs/api/in ...
- java语言规范,main方法必须声明为public
注释: 根据java语言规范,main方法必须声明为public. 当main方法不是public时,有些版本的java解释器也可以执行java应用程序.有个程序员报告了这个bug. 如果感兴趣可以查 ...
- 如何从oracle官网中下载The java language specification(java 语言规范)
第一步: 第二步: 第三步:下面这个图在这个页面的下方,所以你只要一直往下看,直到看到下图的文字为止: 第四步: 第五步: 这样你就可以成功下载该java 语言规范的pdf了. 它直接下载的网址为: ...
- java语言规范
一.标志符 命名规则: 标识符由26个英文字符大小写(a~zA~Z).数字(0~9).下划线(_)和美元符号($)组成. 不能以数字开头,不能是关键字 严格区分大小写 标识符的可以为任意长度 命名规范 ...
- Java语言规范 第3章 词法
- Java多线程(五) —— 线程并发库之锁机制
参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...
- Java语言编码规范(Java Code Conventions)
Java语言编码规范(Java Code Conventions) 名称 Java语言编码规范(Java Code Conventions) 译者 晨光(Morning) 简介 本文档讲述了Java语 ...
- 001-Java®语言规范、Java平台标准版文档、JVM概述
一.概述 相关api地址:JDK10 JDK 9 JDK 8 JDK 7 JDK 6 Java语言和虚拟机规范: https://docs.oracle.com/javase/spec ...
随机推荐
- 聊下git pull --rebase
有一种场景是经常发生的. 大家都基于develop拉出分支进行并行开发,这里的分支可能是多到数十个.然后彼此在进行自己的逻辑编写,时间可能需要几天或者几周.在这期间你可能需要时不时的需要pull下远程 ...
- 基于php基础语言编写的小程序之计算器
基于php基础语言编写的小程序之计算器 需求:在输入框中输入数字进行加.减.乘.除运算(html+php) 思路: 1首先要创建输入数字和运算符的输入框,数字用input的text属性,运算符用sel ...
- redis 源码阅读 数值转字符 longlong2str
redis 在底层中会把long long转成string 再做存储. 主个功能是在sds模块里. 下面两函数是把long long 转成 char 和 unsiged long long 转成 ...
- 在文件夹中 的指定类型文件中 查找字符串(CodeBlocks+GCC编译,控制台程序,仅能在Windows上运行)
说明: 程序使用 io.h 中的 _findfirst 和 _findnext 函数遍历文件夹,故而程序只能在 Windows 下使用. 程序遍历当前文件夹,对其中的文件夹执行递归遍历.同时检查遍历到 ...
- 深入.NET平台的软件系统分成开发(1/6)
第一章软件系统的分层开发 1.1 分成架构 分成模式定义:将解决方案中功能不同的模块分到不同的项目中实现.每一层中的主键应保持内聚性,每一层都应与他下面的各层保持松耦合. 分层模式是最常见的一种架构模 ...
- NOIP2010pj三国游戏[博弈论]
题目描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有 N 位武将(N为偶数且不小于 4),任意两个武将之 ...
- NOIP2009最优贸易[spfa变形|tarjan 缩点 DP]
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- @Autowired 与@Resource的区别
1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下 ...
- .jshintrc配置
在root目录创建一个.jshintrc文件插入下面的代码即可.也可以自行配置. { // // 强制选项 // // When set to true, these options will mak ...
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 适合大型企业信息化应用使用的角色权限管理体系
每个人外表看看都没什么大区别.但是内在的知识.处理问题的能力.解决问题的能力.头脑灵活性都会有很大的差距.软件组件也是一样,有些组件编写厉害,想问题深入,能处理的难题也多,构思巧妙. 通用快速开发平台 ...