Java并发编程:锁的释放
Java并发编程:锁的释放
*/-->
code {color: #FF0000}
pre.src {background-color: #002b36; color: #839496;}
Java并发编程:锁的释放
Table of Contents
上一篇线程的同步,我们讲了锁的获得方式。接下来,我们讲讲锁的释放。首先,锁定的方法或者代码块运行完毕,肯定会释放锁。
那么,主动释放锁,是通过什么方法来达到的呢?
如果,我们看过Object类的方法,我们会注意到它有三个奇怪的方法:wait(),notify()和notifyAll()。 它们就是用来释放锁的。
1 线程的状态
在讲锁的释放前,我们先讲一下线程的三种主要状态:运行、就绪(可运行)、阻塞。当然,除了这个之外,肯定还有初始状态和结束状态,那个就不讨论了。
当我们创建线程之后,还只是进入初始状态,如果我们调用run()方法运行,根本就不会启动新的线程。当调用start()后,可以将线程状态改为可运行状态,然后,由操作系统来决定调用哪个线程。当幸运的被操作系统选中之后,就可以进入真正的运行状态了。当运行当时间片用完,或者调用yield()礼让方法,就会把当前当执行权交出来,进入可运行就绪状态。如果在运行的过程中,有系统IO,如等待输入,弹出确认对话框等,则会使当前线程进入阻塞状态,动弹不得。只有等待用户操作之后,才能往下进行。sleep()方法和join()方法可以可以达到类似的阻塞效果。
然后,我们把对象锁部分的状态也加进来。当我们使用synchronized修饰方法或者代码块时,会获取对象的锁,并进入获取该对象锁的等待池,由操作系统来决定调用哪个线程(非公平锁)。当获取到该对象锁之后,就可以进入可运行状态了。
另外,还有一个对象的wait()方法,可以使线程放弃持有的该对象锁,并进入通知等待状态。当其他线程调用等待线程需要的对象的notify()或者notifyAll()方法时,该线程重新进入获取对象锁的队列中参与锁的获取。
2 wait() notify() 和 notifyAll()
synchronized获取锁的方法我们已经详细的讲解过了,我们接下来来看一下如何主动释放锁。假设,我们想创建两个线程,让这两个线程,依次做一件事情,而不是同时启动之后,就由操作系统来决定它们的执行顺序,那么,我们该怎么做呢?
那就是首先请求前一个线程的锁,然后,获取自己线程的锁,再释放自己的锁,并通知这个锁对象的等待队列(下一个线程!哎哎,醒醒别睡啦,起来干活啦!),释放前一个线程的锁,并进入等待前一个锁对象的通知队列。
用代码展示为:
- public class SyncDemo implements Runnable {
- private String name;
- private Object prev;
- private Object cur;
- public SyncDemo(String name, Object prev, Object cur) {
- this.name = name;
- this.prev = prev;
- this.cur = cur;
- }
- @Override
- public void run() {
- int count = 10;
- while (count > 0) {
- synchronized(prev) {
- synchronized(cur) {
- System.out.println(name);
- count--;
- cur.notify();
- }
- try {
- prev.wait();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- public static void main(String[] args) {
- Object a = new Object();
- Object b = new Object();
- SyncDemo r1 = new SyncDemo("A", b, a);
- SyncDemo r2 = new SyncDemo("B", a, b);
- new Thread(r1).start();
- try {
- Thread.sleep(100);
- } catch (Exception e) {
- e.printStackTrace();
- }
- new Thread(r2).start();
- }
- }
写得更通用一点,支持更多的线程依次执行:
- public static void main(String[] args) {
- int num = 5;
- Object[] locks = new Object[num];
- String[] names = {"A", "B", "C", "D", "E"};
- SyncDemo[] runnable = new SyncDemo[num];
- for (int i = 0; i < num; i++) {
- locks[i] = new Object();
- }
- for (int i = 0; i < num; i++) {
- runnable[i] = new SyncDemo(names[i], locks[(i - 1 + num) % num] , locks[i]);
- }
- for (int i = 0; i < num; i++) {
- new Thread(runnable[i]).start();
- try {
- Thread.sleep(100);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
Date: 2017-07-05 22:31
Author: WEN YANG
Created: 2017-07-07 Fri 21:02
Java并发编程:锁的释放的更多相关文章
- java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock
原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...
- Java并发编程锁之独占公平锁与非公平锁比较
Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...
- Java并发编程锁系列之ReentrantLock对象总结
Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...
- Java 并发编程 | 线程池详解
原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...
- 【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...
- 转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接 ...
- [转载] java并发编程:Lock(线程锁)
作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...
- Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- Java并发编程(十一)-- Java中的锁详解
上一章我们已经简要的介绍了Java中的一些锁,本章我们就详细的来说说这些锁. synchronized锁 synchronized锁是什么? synchronized是Java的一个关键字,它能够将代 ...
随机推荐
- 【NOIP2016提高A组模拟9.17】小a的强迫症
题目 分析 题目要求第i种颜色的最后一个珠子要在第i+1种颜色的最后一个珠子之前, 那么我们从小到大枚举做到第i种,把第i种的最后一颗珠子取出,将剩下的\(num(i)-1\)个珠子插入已排好的前i- ...
- 【leetcode&CN&竞赛】1196.How Many Apples Can You Put into the Basket
题目如下: 楼下水果店正在促销,你打算买些苹果,arr[i] 表示第 i 个苹果的单位重量. 你有一个购物袋,最多可以装 5000 单位重量的东西,算一算,最多可以往购物袋里装入多少苹果. 示例 1: ...
- Redis 历史版本下载URL
Redis 历史版本下载URL: http://download.redis.io/releases/ Redis和RedisClient 官网下载方式: https://blog.51cto.com ...
- 对云信SDK的研究1
1.云信大部分用了jq 2.很多接口 3.是可以文档很健全
- shell练习--PAT题目1007:关于素数对(失败案例)
让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数.显然有d1=1,且对于n>1有dn是偶数.“素数对猜想”认为“存在无穷多对相邻且差为2的素 ...
- Vue结合后台的增删改案例
首先列表内容还是与之前的列表内容类似,不过此处我们会采用Vue中数据请求的方式来实现数据的增删.那么我们使用的Vue第三方组件就是vue-resource,vue发起请求的方式与jQuery的ajax ...
- matlab画二维直方图以及双y轴坐标如何修改另一边y轴的颜色
1.首先讲一下如何用hist画二维直方图 x=[- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...
- AJAX - 服务器 响应
AJAX - 服务器 响应 服务器响应 如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性.大理石构件来图加工 属性 描 ...
- JAVA支持HTTP断点续传
第一点:Java代码实现文件上传 FormFile file = manform.getFile(); String newfileName = null; String newpathname = ...
- Python3学习笔记(六):字符串
一.基本字符串操作 所有标准的序列操作(索引.分片.乘法.判断成员资格.求长度.取最小值和最大值)对字符串同样适用.但是字符串是不可改变的. 二.字符串格式化 字符串格式化使用字符串格式化操作符(%) ...