一、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. 《java入门第一季》之面向对象(接口收尾)

    通过案例的形式,结束接口部分. /* 猫狗案例,加入跳高的额外功能 分析:从具体到抽象 猫: 姓名,年龄 吃饭,睡觉 狗: 姓名,年龄 吃饭,睡觉 由于有共性功能,所以,我们抽取出一个父类: 动物: ...

  2. 【一天一道LeetCode】#31. Next Permutation

    一天一道LeetCode系列 (一)题目 Implement next permutation, which rearranges numbers into the lexicographically ...

  3. Linux内核中SPI总线驱动分析

    本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程): 另一个是SPI总线驱动的编写(不用研究具体的实现过程). 1 SPI概述 SPI是英语Serial Peripheral ...

  4. Java-HttpServletRequest

    //继承了ServletRequest接口,给servlet提供Request请求信息,servlet 容器会创建以后HttpServletRequest对象 //并把它作为一个参数给service函 ...

  5. linux进程的介绍和管理

    概述 -   在linux 中,每个执行的程序都称为一个进程,每一个进程都分配一个ID号 -   每一个进程,都会对应一个父进程,而这个父进程可以复制多个子进程,例如www服务器 -   每个进程都可 ...

  6. OpenCV矩阵运算

    矩阵处理 1.矩阵的内存分配与释放 (1) 总体上: OpenCV 使用C语言来进行矩阵操作.不过实际上有很多C++语言的替代方案可以更高效地完成. 在OpenCV中向量被当做是有一个维数为1的N维矩 ...

  7. 【Android 应用开发】AndroidUI设计之 布局管理器 - 详细解析布局实现

    写完博客的总结 : 以前没有弄清楚的概念清晰化 父容器与本容器属性 : android_layout...属性是本容器的属性, 定义在这个布局管理器的LayoutParams内部类中, 每个布局管理器 ...

  8. java开发中几种常见的线程池

    线程池 java.util.concurrent:Class Executors 常用线程池 几种常用的的生成线程池的方法: newCachedThreadPool newFixedThreadPoo ...

  9. PS 滤镜——素描算法(二)

    利用另外一种算法完成素描特效的生成. %%% Sketch clc; clear all; Image=imread('4.jpg'); Image=double(Image); [row,col,l ...

  10. Linux 系统应用编程——进程基础

    一.Linux下多任务机制的介绍 Linux有一特性是多任务,多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务. 多任务操作系统使用某种调度(shedule)策 ...