ReentrantLock的三种获取锁Lock,tryLock,lockInterruptibly的区别

本文主要是介绍ReentrantLock的三种获取锁Lock,tryLock,lockInterruptibly的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

重入锁有三种获取锁的方式,本文就是来说明三种方式的异同点的.

lock

public void lock()

获得锁。

  • 如果锁没有被另一个线程占用并且立即返回,则将锁定计数设置为1。
  • 如果当前线程已经保持锁定,则保持计数增加1,该方法立即返回。
  • 如果锁被另一个线程保持,则当前线程将被禁用以进行线程调度,并且在锁定已被获取之前处于休眠状态,此时锁定保持计数被设置为1。

tryLock

boolean tryLock();
  • 当获取锁时,只有当该锁资源没有被其他线程持有才可以获取到,并且返回true,同时设置持有count为1。
  • 当获取锁时,当前线程已持有该锁,那么锁可用时,返回true,同时设置持有count加1。
  • 当获取锁时,如果其他线程持有该锁,无可用锁资源,直接返回false,这时候线程不用阻塞等待,可以先去做其他事情。
  • 即使该锁是公平锁fairLock,使用tryLock()的方式获取锁也会是非公平的方式,只要获取锁时该锁可用那么就会直接获取并返回true。这种直接插入的特性在一些特定场景是很有用的。但是如果就是想使用公平的方式的话,可以试一试tryLock(0,TimeUnit.SECONDS),几乎跟公平锁没区别,只是会监测中断事件

使用标准模板:

Lock lock = ...;
if (lock.tryLock()) {try {// manipulate protected state} finally {lock.unlock();}} else {// perform alternative actions}

tryLock的重载方法:

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  • 获取锁成功或者超时之后返回。而且在公平锁和非公平锁的场景下都可以使用,只是会增加对中断事件的监测。
  • 当获取锁时,锁资源在超时时间之内变为可用,并且在等待时没有被中断,那么当前线程成功获取锁,返回true,同时当前线程持有锁的count设置为1.
  • 当获取锁时,在超时时间之内没有锁资源可用,那么当前线程获取失败,不再继续等待,返回false.
  • 当获取锁时,在超时等待时间之内,被中断了,那么抛出InterruptedException,不再继续等待.
  • 当获取锁时,在超时时间之内锁可用,并且当前线程之前已持有该锁,那么成功获取锁,同时持有count加1.

lockInterruptibly

void lockInterruptibly() throws InterruptedException;
  •     当获取锁时,锁资源可用,那么当前线程成功获得锁,同时持有count设置为1,返回true.
  •     当获取锁时,锁资源可用,当前线程已持有该锁,它成功获取该锁,同时持有count增加1,返回true.
  •     当获取锁时,锁资源不可用,那么该线程开始阻塞休眠等待,但是等待过程中如果有中断事件,那么会停止等待,立即返回.
  •     当获取锁时,锁资源不可用,线程开始阻塞休眠等待,如果等待过程中锁资源变为可用,那么当前线程成功获得锁,同时持有count设置为1,返回true.

lockInterruptibly()获取锁是以排他的模式获取,一旦被中断就放弃等待获取。在等待开始时首先检测中断状态,然后至少调用一次tryAcquire,成功获取就返回true。否则当前线程就开始排队,并且不断的被blocking、unblocking、invoking tryAcquire 直到获取成功或者被中断为止。



下面使用代码进行演示:

package com.springcloud.server.springserver.thread;import java.util.concurrent.locks.ReentrantLock;public class TestLockAndTryLock {private ReentrantLock rlock = new ReentrantLock();private void lockTest(){long currentTime = System.currentTimeMillis();try {rlock.lock();while (System.currentTimeMillis() - currentTime <= 1000){//assume do something}System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());}finally {rlock.unlock();System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());}}private void tryLockTest(){long currentTime = System.currentTimeMillis();while (System.currentTimeMillis() - currentTime <= 100){//assume do something}if (rlock.tryLock()){try {System.out.println("tryLockTest----current thread get the lock: " + Thread.currentThread().getName());}finally {rlock.unlock();System.out.println("tryLockTest----current thread release the lock: " + Thread.currentThread().getName());}}else {System.out.println("tryLockTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());}}public static void main(String[] args){TestLockAndTryLock lockAndTryLock = new TestLockAndTryLock();Thread lockThread = new Thread(() -> lockAndTryLock.lockTest(), "Lock-Thread" );Thread tryLockThread = new Thread(() -> lockAndTryLock.tryLockTest(), "TryLock-Thread" );tryLockThread.start();lockThread.start();}}

 输出结果:

lock()方法先获取锁,然后在执行任务的时候阻塞,tryLock()会在尝试加锁失败的时候返回false.

package com.springcloud.server.springserver.thread;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class TestLockAndTryLock1 {private ReentrantLock rlock = new ReentrantLock();private void lockTest(){long currentTime = System.currentTimeMillis();try {rlock.lock();System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());while (System.currentTimeMillis() - currentTime <= 5000){//assume do something}}finally {rlock.unlock();System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());}}private void tryLockInterruptTest(){long currentTime = System.currentTimeMillis();while (System.currentTimeMillis() - currentTime <= 100){//assume do something}try {System.out.println("Begin time: " + System.currentTimeMillis());if (rlock.tryLock(1, TimeUnit.SECONDS)){try {System.out.println("tryLockInterruptTest----current thread get the lock: " + Thread.currentThread().getName());}finally {rlock.unlock();System.out.println("tryLockInterruptTest----current thread release the lock: " + Thread.currentThread().getName());}}else {System.out.println("End time: " + System.currentTimeMillis());System.out.println("tryLockInterruptTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());}} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args){TestLockAndTryLock1 lockAndTryLock = new TestLockAndTryLock1();Thread lockThread = new Thread(() -> lockAndTryLock.lockTest(), "Lock-Thread" );Thread tryLockInterruptThread = new Thread(() -> lockAndTryLock.tryLockInterruptTest(), "TryLockInterrupt-Thread");tryLockInterruptThread.start();lockThread.start();}}

 输出结果:

lock()方法先获取锁,然后执行任务5秒,tryLock()方法先直接获取锁,获取不到就在1秒的时间内持续获取锁,超过时间还获取不到就返回false.

package com.springcloud.server.springserver.thread;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class TestLockAndTryLock2 {private ReentrantLock rlock = new ReentrantLock();private void lockTest(){long currentTime = System.currentTimeMillis();try {rlock.lock();System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());while (System.currentTimeMillis() - currentTime <= 5000){//assume do something}}finally {rlock.unlock();System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());}}private void tryLockInterruptTest(){long currentTime = System.currentTimeMillis();while (System.currentTimeMillis() - currentTime <= 100){//assume do something}try {System.out.println("Begin time: " + System.currentTimeMillis());if (rlock.tryLock(3, TimeUnit.SECONDS)){try {System.out.println("tryLockInterruptTest----current thread get the lock: " + Thread.currentThread().getName());}finally {rlock.unlock();System.out.println("tryLockInterruptTest----current thread release the lock: " + Thread.currentThread().getName());}}else {System.out.println("End time: " + System.currentTimeMillis());System.out.println("tryLockInterruptTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());}} catch (InterruptedException e) {System.out.println("tryLockInterruptTest Interrupt----current thread is interrupted: " + Thread.currentThread().getName());}}public static void main(String[] args){TestLockAndTryLock2 lockAndTryLock = new TestLockAndTryLock2();Thread lockThread = new Thread(() -> lockAndTryLock.lockTest(), "Lock-Thread" );Thread tryLockInterruptThread = new Thread(() -> lockAndTryLock.tryLockInterruptTest(), "TryLockInterrupt-Thread");tryLockInterruptThread.start();lockThread.start();try {Thread.sleep(100);} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + "is interrupted now. ");}tryLockInterruptThread.interrupt();}}

lock()方法先获取锁,然后执行任务5秒,tryLock()方法先直接获取锁,获取不到就在1秒的时间内持续获取锁,在获取锁的过程中,主线程(main)以通知的方式中断tryLockInterruptThread线程,tryLock()方法可以响应中断.


package com.springcloud.server.springserver.thread;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class TestLockInterruptibly {final Lock lock = new ReentrantLock();public static void main(String[] args) throws Exception {TestLockInterruptibly testLockInterruptibly = new TestLockInterruptibly();Thread lockThread = new Thread(() -> testLockInterruptibly.lock());Thread interruptiblyThread = new Thread(() -> testLockInterruptibly.lockInterruptibly());lockThread.start();interruptiblyThread.start();TimeUnit.SECONDS.sleep(2);
//        interruptiblyThread.interrupt();}public void lockInterruptibly()  {long currentTime = System.currentTimeMillis();while (System.currentTimeMillis() - currentTime <= 500){//assume do something}try {lock.lockInterruptibly();System.out.println("lockInterruptibly获取Lock锁");} catch (InterruptedException e) {System.out.println("lockInterruptibly捕捉InterruptedException异常");}finally {lock.unlock();System.out.println("lockInterruptibly释放Lock锁");}}public void lock()  {long currentTime = System.currentTimeMillis();try {lock.lock();System.out.println("lock获取Lock锁");while (System.currentTimeMillis() - currentTime <= 5000){//assume do something}}finally {lock.unlock();System.out.println("lock释放Lock锁");}}}

一般情况下,lockInterruptibly()会阻塞直到获取lock锁,此时和普通的lock()作用差不多,输出结果:

 

当我们打开main方法里面的注释,结果就不一样了,输出结果:

lockInterruptibly()在阻塞的过程中可以响应中断,并可以结束线程.此处抛异常原因是并没有获取锁,却去解锁(unLock()),普通的lock()方法无法响应中断.

 

这篇关于ReentrantLock的三种获取锁Lock,tryLock,lockInterruptibly的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Collection List Set Map的区别和联系

Collection List Set Map的区别和联系 这些都代表了Java中的集合,这里主要从其元素是否有序,是否可重复来进行区别记忆,以便恰当地使用,当然还存在同步方面的差异,见上一篇相关文章。 有序否 允许元素重复否 Collection 否 是 List 是 是 Set AbstractSet 否

javascript中break与continue的区别

在javascript中,break是结束整个循环,break下面的语句不再执行了 for(let i=1;i<=5;i++){if(i===3){break}document.write(i) } 上面的代码中,当i=1时,执行打印输出语句,当i=2时,执行打印输出语句,当i=3时,遇到break了,整个循环就结束了。 执行结果是12 continue语句是停止当前循环,返回从头开始。

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令 在日常的工作中由于各种原因,会出现这样一种情况,某些项目并没有打包至mvnrepository。如果采用原始直接打包放到lib目录的方式进行处理,便对项目的管理带来一些不必要的麻烦。例如版本升级后需要重新打包并,替换原有jar包等等一些额外的工作量和麻烦。为了避免这些不必要的麻烦,通常我们

ActiveMQ—Queue与Topic区别

Queue与Topic区别 转自:http://blog.csdn.net/qq_21033663/article/details/52458305 队列(Queue)和主题(Topic)是JMS支持的两种消息传递模型:         1、点对点(point-to-point,简称PTP)Queue消息传递模型:         通过该消息传递模型,一个应用程序(即消息生产者)可以

深入探讨:ECMAScript与JavaScript的区别

在前端开发的世界中,JavaScript无疑是最受欢迎的编程语言之一。然而,很多开发者在使用JavaScript时,可能并不清楚ECMAScript与JavaScript之间的关系和区别。本文将深入探讨这两者的不同之处,并通过案例帮助大家更好地理解。 一、什么是ECMAScript? ECMAScript(简称ES)是一种脚本语言的标准,由ECMA国际组织制定。它定义了语言的语法、类型、语句、

Lua 脚本在 Redis 中执行时的原子性以及与redis的事务的区别

在 Redis 中,Lua 脚本具有原子性是因为 Redis 保证在执行脚本时,脚本中的所有操作都会被当作一个不可分割的整体。具体来说,Redis 使用单线程的执行模型来处理命令,因此当 Lua 脚本在 Redis 中执行时,不会有其他命令打断脚本的执行过程。脚本中的所有操作都将连续执行,直到脚本执行完成后,Redis 才会继续处理其他客户端的请求。 Lua 脚本在 Redis 中原子性的原因

JS和jQuery获取节点的兄弟,父级,子级元素

原文转自http://blog.csdn.net/duanshuyong/article/details/7562423 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。 JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素。 <div id="test"><div></div><div></div