lock()和lockInterruptible()都表示获取锁,唯一区别是,当A线程调用lock()或lockInterruptible()方法获取锁没有成功而进入等待锁的状态时,若接着调用该A线程的interrupt()方法中断该线程的等待:
  • 如果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()有什么区别?的更多相关文章

  1. java多线程(死锁,lock接口,等待唤醒机制)

    一.Lock接口 常用方法 Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能. 使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Tic ...

  2. java 线程(五)线程安全 Lock接口

    package cn.sasa.demo3; import java.util.concurrent.ExecutionException; public class ThreadDemo { pub ...

  3. Lock接口简介

    在Java多线程编程中,我们经常使用synchronized关键字来实现同步,控制多线程对变量的访问,来避免并发问题. 但是有的时候,synchronized关键字会显得过于沉重,不够灵活.synch ...

  4. 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

    欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...

  5. synchronized关键字,Lock接口以及可重入锁ReentrantLock

    多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...

  6. 线程同步 Lock接口

    同步:★★★★★ 好处:解决了线程安全问题. 弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁. 定义同步是有前提的: 1,必须要有两个或者两个以上的线程,才需要同步. 2,多个线程必须保证使用 ...

  7. Java基础知识强化之多线程笔记06:Lock接口 (区别于Synchronized块)

    1. 简介 我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式 ...

  8. Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock

    在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...

  9. jdk1.5多线程Lock接口及Condition接口

    jdk1.5多线程的实现的方式: jdk1.5之前对锁的操作是隐式的 synchronized(对象) //获取锁 { } //释放锁 jdk1.5锁的操作是显示的:在包java.util.concu ...

随机推荐

  1. C++11移动语义之一(基本概念)

    摘要 移动语义是C++11的新特性之一,利用移动语义可以实现对象的移动而非拷贝.在某些情况下,可以大幅度的提升性能.本文将介绍C++11移动语义中的一些基本概念. 表达式 表达式是由一个或者多个运算对 ...

  2. 解释JDBC抽象和DAO模块?

    通过使用JDBC抽象和DAO模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层.它还利用Spring的AOP 模块给Spr ...

  3. Oracle入门基础(五)一一多表查询

    SQL> --等值连接 SQL> --查询员工信息:员工号 姓名 月薪 部门名称 SQL> set linesize 80 SQL> desc dept 名称 是否为空? 类型 ...

  4. Oracle入门基础(四)一一多行函数

    SQL> --工资总额 SQL> select sum(sal) from emp; SUM(SAL) 29025 SQL> --人数 SQL> select count(*) ...

  5. java中如何获得src路径

    代码 解析: 类名.class.get类加载器().getResourceAsStream("文件名"); 案例代码: Demo.class.getClassLoader().ge ...

  6. 决策树算法2:(增益比率C4.5)

    最重要的是第一个 改进1:信息增益率代替信息增益来选择属性 改进2:连续属性与分裂点 计算的是以候选点(划分点)划分的划分点的条件信息熵 改进三:缺失值处理 众数:概率值-缺失值将缺失值当作单独分类, ...

  7. IMWeb前端提升营七天学习总结

    写在前面 5月24到30这7天,IMWeb前端提升营,腾讯大佬们分享个人经验,使出各种前端方面的大招.从中学习了很多前端方面的知识,也get到了前端学习的方法论,还有一些算法知识等等. 现将总结如下: ...

  8. vue全家桶+axios+jsonp+es6 仿肤君试用小程序

    vue全家桶+axios+jsonp+es6 仿肤君试用小程序 把自己写的一个小程序项目用vue来实现的,代码里面有一些注释,主要使用了vue-cli,vue,vuex,vue-router,axoi ...

  9. js 图片上传给后台的3种格式

    1. file格式 (创建formData来完成file上传) 我们的接口需求: 代码: <input type="file" id="imgfile" ...

  10. Mysql_事务_存储过程_触发器

    一.什么是事务? 事务(Transaction),一般是指要做的或所做的事情.在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务通常由高级数据库操纵语言或编程语言( ...