一、ReentrantLock简介

  ReentrantLock字面意义上理解为可重入锁。那么怎么理解可重入这个概念呢?或者说和我们经常用的synchronized又什么区别呢?

  ReentrantLock可重入锁是一种递归无阻塞的同步锁机制,简单意思就是说可重入锁就是当前持有该锁的线程能够多次获取该锁,无需等待。它可以等同于synchronized的作用,但是它比synchronized更加的灵活,更加的强大,能够更好的降低死锁发生的概率。

二、ReentrantLock使用和Lock接口中的API介绍

  2.1、构造方法

  ReentrantLock是lock接口的实现类。

  无参数构造。直接返回ReentrantLock锁的实例。

  有参数构造。支持传入一个boolean类型的参数表示这个锁是公平锁还是非公平锁。ReentrantLock默认是非公平锁。设置参数为true表示为公平锁。

  2.2、lock()方法

  lock方法表示当前线程去获取锁。不能获取到锁则等待。需要注意的是ReentrantLock锁需要我们手动的释放锁,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

  

         ReentrantLock lock = new ReentrantLock();
lock.lock();//获取锁
try{
//处理业务
}catch (Exception e){ }finally {
lock.unlock();//释放锁
}

  2.3、tryLock()方法

  由于lock方法获取锁以后只能一直等待。这样有些不太友好。提供了tryLock方法。该方法会提供一个boolean返回值。为true表示获取锁成功,为false则表示获取锁失败了。这样可以避免一直无脑的等待锁。同时tryLock提供了一个重载方法tryLock(long time, TimeUnit unit)。tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

         if (lock.tryLock()){
try {
//得到锁 处理业务
} catch(Exception e){ } finally {
lock.unlock();
}
}else{
//没有获取到锁,先执行其他的任务
}

  2.4、lockInterruptibly()方法。响应中断操作

  当通过这个锁去获取锁的时候可以响应的中断操作,意思就是当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。这个过程叫做中断自己,会捕获到InterruptedException异常。注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。

三、ReentrantLock类简单使用

  前面有说了该类主要是更加灵活的使用synchronized同步锁。

 

 import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock; public class TestReentrantLock {
public static List<Integer> list = new ArrayList<>();
public ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
TestReentrantLock addThread = new TestReentrantLock();
new Thread(){
public void run(){
//addThread.insert(Thread.currentThread());
addThread.tryInsert(Thread.currentThread());
}
}.start(); new Thread(){
public void run(){
//addThread.insert(Thread.currentThread());
addThread.tryInsert(Thread.currentThread());
}
}.start();
} /**
* 只有一个线程能够对list集合进行增加操作
*/
public void insert(Thread thread){ lock.lock();
try{
System.out.println("当前线程:"+thread.getName()+"获取了锁");
for (int i = 0;i < 10;i++){
list.add(i);
}
}catch (Exception e){ }finally {
System.out.println("当前线程:"+thread.getName()+"释放了锁");
lock.unlock();
} } /**
* 尝试插入数据。如果当前不让插入数据。则去做其他业务
* @param thread
*/
public void tryInsert(Thread thread){
if (lock.tryLock()){
try{
System.out.println("当前线程:"+thread.getName()+"获取了锁");
for (int i = 0;i < 10;i++){
list.add(i);
}
}catch (Exception e){ }finally {
System.out.println("当前线程:"+thread.getName()+"释放了锁");
lock.unlock();
}
}else{
System.out.println("线程"+thread.getName()+"获取锁失败");
}
} }
线程Thread-1获取锁失败
当前线程:Thread-0获取了锁
当前线程:Thread-0释放了锁

四、(Lock接口)ReentrantLock和synchronized的一些比较

  4.1、Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现。

  4.2、synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁。

  4.3、Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断。

  4.4、通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

  

 

Java并发之ReentrantLock的更多相关文章

  1. java并发之ReentrantLock学习理解

    简介 java多线程中可以使用synchronized关键字来实现线程间同步互斥,但在jdk1.5中新增加了ReentrantLock类也能实现同样的效果,并且在扩展功能上也更加强大,比如具有嗅探锁定 ...

  2. Java并发之ReentrantLock详解

    一.入题 ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,以lock()为例,其使用方式为: ReentrantLock takeLock = new Reent ...

  3. Java并发之ReentrantLock源码解析(一)

    ReentrantLock ReentrantLock是一种可重入的互斥锁,它的行为和作用与关键字synchronized有些类似,在并发场景下可以让多个线程按照一定的顺序访问同一资源.相比synch ...

  4. Java并发之ReentrantLock源码解析(二)

    在了解如何加锁时候,我们再来了解如何解锁.可重入互斥锁ReentrantLock的解锁方法unlock()并不区分是公平锁还是非公平锁,Sync类并没有实现release(int arg)方法,这里会 ...

  5. Java并发之ReentrantLock源码解析(三)

    ReentrantLock和BlockingQueue 首先,看到这个标题,不要怀疑自己进错文章,也不要怀疑笔者写错,哈哈.本章笔者会从BlockingQueue(阻塞队列)的角度,看看juc包下的阻 ...

  6. Java并发之ReentrantLock源码解析(四)

    Condition 在上一章中,我们大概了解了Condition的使用,下面我们来看看Condition再juc的实现.juc下Condition本质上是一个接口,它只定义了这个接口的使用方式,具体的 ...

  7. JAVA并发之阻塞队列浅析

    背景 因为在工作中经常会用到阻塞队列,有的时候还要根据业务场景获取重写阻塞队列中的方法,所以学习一下阻塞队列的实现原理还是很有必要的.(PS:不深入了解的话,很容易使用出错,造成没有技术深度的样子) ...

  8. java并发之CopyOnWirteArrayList

    java并发之CopyOnWirteArrayList CopyOnWirteArrayList的实现 它用了ReentrantLock保证了add,set,remove操作的安全,同时使用volat ...

  9. Java并发之显式锁和隐式锁的区别

    Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchr ...

随机推荐

  1. Spring揭秘 读书笔记 五 容器的启动

    Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系.它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定 ...

  2. Leetcode_141_Linked List Cycle

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42833739 Given a linked list, d ...

  3. android动画介绍之 自定义Animation动画实现qq抖一抖效果

    昨天我们介绍了Animation的基本用法.小伙伴们了解的怎么样了?如果还没有了解过Animation的小伙伴可以看看这篇博客 android动画介绍--Animation 实现loading动画效果 ...

  4. CentOS 7下的Vim自动补齐插件YouCompleteMe安装及配置

    备注:现在对于 YouCompleteMe 的安装应采用更为简单的方法,即利用 Vundle 来安装这个插件.具体方法可见: Vundle 主页 YouCompleteMe 主页 而 .vimrc 的 ...

  5. 不用局部变量实现C语言两数交换算法

    关于交换算法,我想非常简单,所以,这次不做分析,直接上代码: #include <stdio.h> #include <stdlib.h> //用异或方式实现 void swa ...

  6. LeetCode之“动态规划”:Scramble String

    题目链接 题目要求: Given a string s1, we may represent it as a binary tree by partitioning it to two non-emp ...

  7. “《编程珠玑》(第2版)第2章”:B题(向量旋转)

    B题是这样子的: 将一个n元一维向量向左旋转(即循环移位)i个位置.例如,当n=8且i=3时,向量abcdefgh旋转为defghabc.简单的代码使用一个n元的中间向量在n步内完成该工作.你能否仅使 ...

  8. Universal-Image-Loader源码分析,及常用的缓存策略

    讲到图片请求,主要涉及到网络请求,内存缓存,硬盘缓存等原理和4大引用的问题,概括起来主要有以下几个内容: 原理示意图 主体有三个,分别是UI,缓存模块和数据源(网络).它们之间的关系如下: ① UI: ...

  9. caffe中是如何运用protobuf构建神经网络的?

    caffe这个框架设计的比较小巧精妙,它采用了protobuf来作为交互的媒介,避免了繁重的去设计各个语言的接口,开发者可以使用任意语言通过这个protobuf这个媒介,来运行这个框架. 我们这里不过 ...

  10. webpack安装使用

    一.安装 1.安装node.js,Webpack 需要 Node.js v0.6 以上支持 2.使用npm(软件包管理 )安装webpack (1)全局安装    npm install webpac ...