聊聊Lock接口的lock()和lockInterruptible()有什么区别?
- 如果A线程是通过lock()获取锁失败而进入等待状态的:则A线程不会马上执行自己的interrupt()方法去中断等待,而是继续等待获取锁(同时把中断命令放入等待队列), 获取到锁之后才响应自己的interrupt()方法去中断等待(从等待丢列中拿出中断命令执行)。获取锁之后,若A线程没有处于等待状态而调用interrupt()方法,是不会发生任何事情的,若获取锁之后A刚刚好又进入了等待状态,则执行等待丢列中的中断命令就会让A抛出InterruptedException()异常去中断等待
- 如果A线程是想通过lockInterruptible()获取锁失败而进入等待状态的:则A线程会马上响应自己的interrupt()方法抛出InterruptedException 异常去中断等待,此时在finally里处理该异常,从而接着执行其他的代码
使用lockInterruptible()获取锁的例子:
public class LockTest {
private Lock lock = new ReentrantLock();
public void doBussiness() {
String name = Thread.currentThread().getName();
try {
System.out.println(name + " 开始获取锁");
lock.lockInterruptibly();//获取锁,可以调interrupt()中断等待
System.out.println(name + " 得到锁");
System.out.println(name + " 开工干活");
for (int i=0; i<5; i++) {
Thread.sleep(1000);
System.out.println(name + " : " + i);
}
} catch (InterruptedException e) {
//用lockInterruptibly()获取锁,必须处理可能调用interrupt()而抛出的InterruptedException异常
System.out.println(name + " 被中断");
System.out.println(name + " 做些别的事情");
} finally {
try {
lock.unlock();
System.out.println(name + " 释放锁");
} catch (Exception e) {
System.out.println(name + " : 没有得到锁的线程运行结束");
}
}
}
public static void main(String[] args) throws InterruptedException {
LockTest lockTest = new LockTest();
Thread t0 = new Thread(
new Runnable() {
public void run() {
lockTest.doBussiness();
}
}
);
Thread t1 = new Thread(
new Runnable() {
public void run() {
lockTest.doBussiness();
}
}
);
// 启动线程t1
t0.start();
Thread.sleep(10);
// 启动线程t2
t1.start();
Thread.sleep(100);
// 线程t1没有得到锁,中断t1的等待
t1.interrupt();
}
}
#运行结果:
Thread-0 开始获取锁
Thread-0 得到锁
Thread-0 开工干活
Thread-1 开始获取锁
Thread-1 被中断 //线程t1用lockInterruptible()获取锁失败而进入等待时,主线程调用t1.interrupt()使该t1抛出异常从而中断等待
Thread-1 做些别的事情//t1中断等待后接着执行其他的代码
Thread-1 : 没有得到锁的线程运行结束
Thread-0 : 0
Thread-0 : 1
Thread-0 : 2
Thread-0 : 3
Thread-0 : 4
Thread-0 释放锁
使用lock()获取锁的例子:
把上面第9行中lock.lockInterruptibly()改为lock.lock(),其他代码不变,则输出结果: Thread-0 开始获取锁
Thread-0 得到锁
Thread-0 开工干活
Thread-1 开始获取锁 //t0已经获取到了锁,所以t1只能进入等待状态(线程没有获取到锁会进入等待状态)。因为t1是调用lock.lock()获取锁的,所以即便主线程调用t1.interrupt()方法,t1也不会马上响应中断(即抛出InterruptedException异常来中断自己的等待状态),而是直到拿到锁之后才会响应中断
Thread-0 : 0
Thread-0 : 1
Thread-0 : 2
Thread-0 : 3
Thread-0 : 4
Thread-1 得到锁 //t0打印完后已经执行了lock.unlock()释放了锁,要不然t1是拿不到锁的。同时t0还没来得及执行上面第23行代码用System打印出“Thread-0 释放锁”,时间片就轮给了t1,所以这行代码是t1执行输出的
Thread-1 开工干活
Thread-1 被中断 //由于t1拿到锁后才会去响应中断,所以上面第13行Thread.sleep(1000)在t1拿到锁之后又让t1进入了等待状态,此时t1刚刚好执行响应中断,故抛出InterruptedException来异常响应中断
Thread-1 做些别的事情
Thread-0 释放锁
Thread-1 释放锁 //t0早就释放了锁,在这里重新获得了时间片进行打印操作
聊聊Lock接口的lock()和lockInterruptible()有什么区别?的更多相关文章
- java多线程(死锁,lock接口,等待唤醒机制)
一.Lock接口 常用方法 Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能. 使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Tic ...
- java 线程(五)线程安全 Lock接口
package cn.sasa.demo3; import java.util.concurrent.ExecutionException; public class ThreadDemo { pub ...
- Lock接口简介
在Java多线程编程中,我们经常使用synchronized关键字来实现同步,控制多线程对变量的访问,来避免并发问题. 但是有的时候,synchronized关键字会显得过于沉重,不够灵活.synch ...
- 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础
欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...
- synchronized关键字,Lock接口以及可重入锁ReentrantLock
多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...
- 线程同步 Lock接口
同步:★★★★★ 好处:解决了线程安全问题. 弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁. 定义同步是有前提的: 1,必须要有两个或者两个以上的线程,才需要同步. 2,多个线程必须保证使用 ...
- Java基础知识强化之多线程笔记06:Lock接口 (区别于Synchronized块)
1. 简介 我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式 ...
- Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock
在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...
- jdk1.5多线程Lock接口及Condition接口
jdk1.5多线程的实现的方式: jdk1.5之前对锁的操作是隐式的 synchronized(对象) //获取锁 { } //释放锁 jdk1.5锁的操作是显示的:在包java.util.concu ...
随机推荐
- [MRCTF]XOR-无法生成反汇编的处理
主程序,无法生成伪代码 由此分为两种方法即: 直接看反汇编 解决问题,尝试生成伪代码 硬啃汇编 输入与输出 判断输入长度是否为0x1B,其中al为eax的低8位 将输入的字符每个与当前字符所在下标异或 ...
- VS2012 生成可以在XP下运行的exe文件
1. 在已安装VS2012条件下,安装update,作者已经安装了update3; 2. 相关设置: 设置"平台工具集":在项目右击-属性-常规-在"平台工具集" ...
- ClassLoader如何加载class ?
jvm里有多个类加载,每个类加载可以负责加载特定位置的类,例如,bootstrap类加载负责加载jre/lib/rt.jar中的类, 我们平时用的jdk中的类都位于rt.jar中.extclasslo ...
- 为什么要使用 kafka,为什么要使用消息队列?
缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理. 解耦 ...
- 使用 JDBC 操作数据库时,如何提升读取数据的性能?如 何提升更新数据的性能?
要提升读取数据的性能,可以指定通过结果集(ResultSet)对象的 setFetchSize() 方法指定每次抓取的记录数(典型的空间换时间策略):要提升更新数据的性能 可以使用 PreparedS ...
- elasticsearch 是如何实现 master 选举的 ?
面试官:想了解 ES 集群的底层原理,不再只关注业务层面了. 前置前提: 1.只有候选主节点(master:true)的节点才能成为主节点. 2.最小主节点数(min_master_nodes)的目的 ...
- mysql学习 | LeetCode数据库简单查询练习
力扣:https://leetcode-cn.com/ 力扣网数据库练习:https://leetcode-cn.com/problemset/database/ 文章目录 175. 组合两个表 题解 ...
- ES6-11学习笔记--const
新声明方式:const 1.不属于顶层对象 window 2.不允许重复声明 3.不存在变量提升 4.暂时性死区 5.块级作用域 以上特性跟let声明一样,特性可看 let 的学习笔记:链接跳转 ...
- 【Android开发】用WebView访问证书有问题的SSL网页
Android系统的碎片化很严重,并且手机日期不正确.手机根证书异常.com.google.android.webview BUG等各种原因,都会导致WebViewClient无法访问HTTPS站点. ...
- vue配置请求转发解决跨域问题
通过nodejs的请求转发到后台,前端地址:http://localhost:8080 后端地址:http://localhost:8081 vue.config.js内容如下: let prox ...