在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock。它们分别实现接口Lock和ReadWriteLock。(注意:synchronized也是可重入锁)

public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
* @return the lock used for reading
*/
Lock readLock(); /**
* Returns the lock used for writing.
* @return the lock used for writing
*/
Lock writeLock();
}

在此之前我们一直使用的是“内置锁”,也就是synchronized来保证线程安全性的。那么为什么会引入显示锁呢?毕竟synchronized用起来还是十分的简单,好用的(自动获取锁,自动释放锁,简化编程,减少错误)。但是synchronized简单好用的同时,在功能上却不足,存在局限性:

1)synchronized在申请锁如果被阻塞时,无法被中断;而Lock.lockInterruptibly()是可中断的锁;

2)synchronized无法实现轮询锁和限时锁;而使用显示锁的 Lock.tryLock() 配合 sleep() 和 while(true) 可以实现轮询锁;Lock.tryLock(long time, TimeUnit unit)实现了限时锁的功能;

3)另外显示锁的引入了,使我们可以方便实现细粒度的锁定;

4)读写锁的引入能够在读多写少的时提供更好的性能;synchronized和Lock对于“读读”环境也是互斥的;

5)另外显示锁,是我们可以使用“公平锁”;

但是,显示锁的引入也导致了编程的复杂,容易出错,容易导致没有释放锁。必须要使用try{}finally{}来保证锁被释放掉:

        Lock lock = new ReentrantLock();
lock.lock();
try{
// access the resource protected by this lock
}finally{
lock.unlock();
}
        if(lock.tryLock()){
try{
// ... ...
}finally{
lock.unlock();
}
}

要使用公平锁,需要传入参数:true,我们看一下他们的构造函数:

    /**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
} /**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

默认的 new ReentrantLock(); 获得的是非公平锁。new ReentrantLock(true); 获得的才是公平锁。

所谓“公平锁”是指多个线程在等待同一个锁时,按照申请的先后顺序排队,先申请的线程先获得该锁。不允许插队。但是因为“公平锁”会导致过多的线程上下文切换,从而性能不好。所以一般使用非公平锁。

synchronized 和 ReentrantLock 在“同步”的功能上是等价的。性能方面在java1.6之后也是相似的。在java1.5中显示锁有优势。

所谓的“可重入锁”,是指同一个线程在已经获得了一个对象的锁时,可以再次获得该对象上的锁,不会阻塞。实现原理是,在ReentrantLock中保存了锁的拥有者 owner 和 锁被获取的次数。

总结:

内置锁synchronized,具有简单,好用,不易出错等优点,但是在功能方面有缺陷,不灵活;而显示锁ReentrantLock功能强大,十分灵活,但是编程容易出错。性能方面在java1.6之后两者差别很小,所以在一般情况下,我们会使用内置锁synchronized,只有在synchronized不能满足我们的功能需求时,才会使用显示锁ReentrantLock。

Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock的更多相关文章

  1. 多线程并发编程之显示锁ReentrantLock和读写锁

    在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock. ReentrantLock概况 ReentrantLock是 ...

  2. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

  3. Java中的各种锁--分类总结

    前言 本文需要具备一定的多线程基础才能更好的理解. 学习java多线程时,最头疼的知识点之一就是java中的锁了,什么互斥锁.排它锁.自旋锁.死锁.活锁等等,细分的话可以罗列出20种左右的锁,光是看着 ...

  4. Java 中的各种锁和 CAS + 面试题

    Java 中的各种锁和 CAS + 面试题 如果说快速理解多线程有什么捷径的话,那本文介绍的各种锁无疑是其中之一,它不但为我们开发多线程程序提供理论支持,还是面试中经常被问到的核心面试题之一.因此下面 ...

  5. Java中15种锁的介绍

    作者:搜云库技术团队 原文:https://segmentfault.com/a/1190000017766364 1. Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观 ...

  6. 分门别类总结Java中的各种锁,让你彻底记住

    概念 公平锁/非公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁. 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁.有可能,会造成优先级反转或者饥 ...

  7. 轻松学习java可重入锁(ReentrantLock)的实现原理

    转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...

  8. java 可重入锁ReentrantLock的介绍

    一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...

  9. 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)

    前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...

随机推荐

  1. 一秒钟生成自己的iOS客户端

    原谅我这个标题党 想当年我也是亲自学过几天Objective-c的程序猿,我一眼就知道我是在骗人,但那有怎样呢!还不是满大街都是各种<十分钟让你明白Objective-C的语法>.< ...

  2. 浅谈mysql的两阶段提交协议

    前两天和百度的一个同学聊MySQL两阶段提交,当时自信满满的说了一堆,后来发现还是有些问题的理解还是比较模糊,可能是因为时间太久了,忘记了吧.这里再补一下:) 5.3.1事务提交流程 MySQL的事务 ...

  3. 反射动态创建不同的Processor

    1. 定义抽象方法 public abstract class BaseProcesser    {        public abstract void GetCustomerReportCard ...

  4. dos系统

    实验一  命令解释程序的编写 一.目的和要求 1. 实验目的 (1)掌握命令解释程序的原理: (2)掌握简单的DOS调用方法: (3)掌握C语言编程初步. 2.实验要求 编写类似于DOS,UNIX的命 ...

  5. 第一个sprint总结和读后感

    总结:通过第一个sprint的冲刺,了解了sprint的整个流程,学会了在一个团队里该如何开展一个项目和分配任务.我们的队团在第一个sprint中没有达到我们预期的效果,我们也做出了反省,原因一是我们 ...

  6. 0527Sprint总结,读书笔记与提问

    第八章主要软件团队如何准确全面的找到人们对于软件五花八门的需求,主要有以下几个步骤: 1.获取和引导需求 2.分析和定义需求 3.验证需求 4.在软件产品的生命周期中管理需求 . 接下来讲了软件产品的 ...

  7. 在ASP.NET MVC环境中使用加密与解密

    在.NET Framework 4.5的NET框架中,在程序中加密与解密很方便.现在均学习ASP.NET MVC程序了,因此Insus.NET也在此写个学习的例子.在需要时可以参考与查阅. 写一个Ut ...

  8. 批量插入数据 C# SqlBulkCopy使用

    转自:http://blog.csdn.net/wangzh300/article/details/7382506 private static void DataTableToSQLServer( ...

  9. 自己通过Cygwin编译的windows下的redis3.2.6

    采用方法:https://my.oschina.net/maxid/blog/186506 方法中在3.2.6未找到src/redis.h文件 未修改 方法中 /deps/hiredis/net.c ...

  10. UUID(uuid)js 生成

    全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) . GUID是一种由算法生成的二进制长度 ...