目录

重入锁

简单重入锁

重入锁的等待通知(Condition)

多Condition

公平锁和非公平锁

读写锁ReentrantReadWriteLock

锁优化总结:


重入锁和读写锁,他们具有比synchronized更为强大的功能,并且有嗅探锁定、多路分支等功能。

重入锁

在需要进行同步的代码部分加上锁定,但不要忘记最后一定要释放锁定,不然会造成锁永远无法释放,其他线程永远进不来的结果。

简单重入锁

//一定要在finally中解锁
//感觉跟synchronized没啥区别,是对象锁。也许性能比较好一些
public class UseReentrantLock {//private Lock lock = new ReentrantLock();//定义一个锁冲突public void method1(){Lock lock = new ReentrantLock();//定义两个锁不冲突try {lock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入method1..");Thread.sleep(1000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "退出method1..");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void method2(){Lock lock = new ReentrantLock();//定义两个锁不冲突try {lock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入method2..");Thread.sleep(2000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "退出method2..");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String[] args) {final UseReentrantLock ur = new UseReentrantLock();final UseReentrantLock ur2 = new UseReentrantLock();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {ur.method1();}}, "t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {ur2.method2();}}, "t2");t1.start();t2.start();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//System.out.println(ur.lock.getQueueLength());}
}

重入锁的等待通知(Condition)

就像synchronized,wait()、notify()、notifyAll()。

同样,在使用Lock的时候,可以使用一个新的等待/通知的类,它就是Condition。这个Condition一定是针对具体某一把锁的。也就是在只有锁的基础之上才会产生Condition。

public class UseCondition {private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void method1(){try {lock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入等待状态..");Thread.sleep(3000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "释放锁..");condition.await();   // Object waitSystem.out.println("当前线程:" +  Thread.currentThread().getName() +"继续执行...");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void method2(){try {lock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入..");Thread.sleep(3000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "发出唤醒..");condition.signal();        //Object有notifyAll,同理这里也有signalAll()方法} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String[] args) {final UseCondition uc = new UseCondition();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {uc.method1();}}, "t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {uc.method2();}}, "t2");t1.start();t2.start();}
}

多Condition

我们可以通过一个Lock对象产生多个Condition进行多线程间的交互,非常的灵活。可以使得部分需要唤醒的线程唤醒,其他线程则继续等待通知。

//两个Condition是独立的!!!
public class UseManyCondition {private ReentrantLock lock = new ReentrantLock();private Condition c1 = lock.newCondition();private Condition c2 = lock.newCondition();public void m1(){try {lock.lock();System.out.println("当前线程:"  +Thread.currentThread().getName() + "进入方法m1等待..");c1.await();System.out.println("当前线程:"  +Thread.currentThread().getName() + "方法m1继续..");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void m2(){try {lock.lock();System.out.println("当前线程:"  +Thread.currentThread().getName() + "进入方法m2等待..");c1.await();System.out.println("当前线程:"  +Thread.currentThread().getName() + "方法m2继续..");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void m3(){try {lock.lock();System.out.println("当前线程:"  +Thread.currentThread().getName() + "进入方法m3等待..");c2.await();System.out.println("当前线程:"  +Thread.currentThread().getName() + "方法m3继续..");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void m4(){try {lock.lock();System.out.println("当前线程:"  +Thread.currentThread().getName() + "唤醒..");c1.signalAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void m5(){try {lock.lock();System.out.println("当前线程:"  +Thread.currentThread().getName() + "唤醒..");c2.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public static void main(String[] args) {final UseManyCondition umc = new UseManyCondition();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {umc.m1();}},"t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {umc.m2();}},"t2");Thread t3 = new Thread(new Runnable() {@Overridepublic void run() {umc.m3();}},"t3");Thread t4 = new Thread(new Runnable() {@Overridepublic void run() {umc.m4();}},"t4");Thread t5 = new Thread(new Runnable() {@Overridepublic void run() {umc.m5();}},"t5");t1.start();     // c1t2.start();     // c1t3.start();     // c2try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}t4.start();     // c1try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}t5.start();     // c2}
}

公平锁和非公平锁

默认是非公平,非公平锁效率比较高。

Lock lock = new ReentrantLock(boolean isFair);//可传参,默认是false非公平锁。

lock用法:

tryLock():尝试获得锁,获得结果用true/false返回。

tryLock():在给定的时间内尝试获得锁,获得结果用true/false返回。

isFair():是否是公平锁。

isLocked():是否锁定。

getHoldCount():查询当前线程保持此锁的个数,也就是调用lock()次数。

lockInterruptibly():优先响应中断的锁。

getQueueLength():返回正在等待获取此锁的线程数。

getWaitQueueLength():返回等待与锁定相关的给定条件Condition的线程数。

hasQueuedThread(Thread thread):查询指定的线程是否在等待此锁。

hasQueuedThreads():查询是否有线程正在等待此锁。

hasWaiters():查询是否有线程正在等待与此锁定有关的condition条件。

读写锁ReentrantReadWriteLock

读写锁ReentrantReadWriteLock,其核心就是实现读写分离的锁。在高并发访问下,尤其是读多写少的情况下,性能要远高于重入锁。

之前的synchronized、ReentrantLock,我们知道,同一时间内只能有一个线程进行访问被锁定的代码,那么读写锁则不同,其本质是分成两个锁,即读锁、写锁。在读锁下,多个线程可以并发的进行访问,但是在写锁的时候,只能一个个的顺序访问。

口诀:读读共享,写写互斥,读写互斥

public class UseReentrantReadWriteLock {private ReentrantReadWriteLock rwLock = new  ReentrantReadWriteLock();private ReadLock readLock = rwLock.readLock();private WriteLock writeLock = rwLock.writeLock();public void read(){try {readLock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入...");Thread.sleep(3000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "退出...");} catch (Exception e) {e.printStackTrace();} finally {readLock.unlock();}}public void write(){try {writeLock.lock();System.out.println("当前线程:" +  Thread.currentThread().getName() + "进入...");Thread.sleep(3000);System.out.println("当前线程:" +  Thread.currentThread().getName() + "退出...");} catch (Exception e) {e.printStackTrace();} finally {writeLock.unlock();}}public static void main(String[] args) {final UseReentrantReadWriteLock urrw = new  UseReentrantReadWriteLock();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {urrw.read();}}, "t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {urrw.read();}}, "t2");Thread t3 = new Thread(new Runnable() {@Overridepublic void run() {urrw.write();}}, "t3");Thread t4 = new Thread(new Runnable() {@Overridepublic void run() {urrw.write();}}, "t4");       //         t1.start();// R
//         t2.start();// R//         t1.start(); // R
//         t3.start(); // Wt3.start();// Wt4.start();// W}
}

锁优化总结:

1.避免死锁。

2.减小锁的持有时间。

3.减小锁的粒度。

4.锁的分离(读写锁)。

5.尽量使用无锁的操作,如原子操作(Atomic系列类),volatile关键字。

谈谈java并发锁(重入锁、读写锁、公平锁)相关推荐

  1. java writelock 问题_【转】java并发编程系列之ReadWriteLock读写锁的使用

    前面我们讲解了Lock的使用,下面我们来讲解一下ReadWriteLock锁的使用,顾明思义,读写锁在读的时候,上读锁,在写的时候,上写锁,这样就很巧妙的解决synchronized的一个性能问题:读 ...

  2. Java并发教程–重入锁

    Java的synced关键字是一个很棒的工具–它使我们能够以一种简单可靠的方式来同步对关键部分的访问,而且也不难理解. 但是有时我们需要对同步进行更多控制. 我们要么需要分别控制访问类型(读取和写入) ...

  3. java lock可重入_一文彻底理解ReentrantLock可重入锁的使用

    java除了使用关键字synchronized外,还可以使用ReentrantLock实现独占锁的功能.而且ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也 ...

  4. 12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁

    小陈:呼叫老王...... 老王:来了来了,小陈你准备好了吗?今天我们来讲synchronized的锁重入.锁优化.和锁升级的原理 小陈:早就准备好了,我现在都等不及了 老王:那就好,那我们废话不多说 ...

  5. java读写锁死锁例子_Java并发关于重入锁与读写锁的详解

    这篇文章主要介绍了Java并发编程之重入锁与读写锁,文中相关实例代码详细,测试可用,具有一定参考价值,需要的朋友可以了解下. 重入锁 重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对 ...

  6. 深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/75043422 出自[zejian ...

  7. Java ReentrantLock可重入锁的源码深度解析

    Java的ReentrantLock的源码实现,包括加锁.解锁的源码,以及公平性.重入性的实现! 文章目录 1 ReentrantLock的概述 1.1 ReentrantLock的API方法 1.2 ...

  8. 【转载】Java多线程编程2--同步锁定--synchronized同步方法、脏读、锁重入

        线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 1.方法内的变量为线程安全   "非线程安全"问题存在于"实例变量"中,如果是方法内 ...

  9. Java 学习笔记之 Synchronized锁重入

    Synchronized锁重入: 当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁.这也证明在一个Synchronized方法/块的内部调用本类的其他Synchronized方法 ...

最新文章

  1. RedisJson 横空出世,性能碾压ES和Mongo!
  2. 42张图详解 NAT : 换个马甲就能上网
  3. 20行python代码的入门级小游戏-200行Python代码实现的2048小游戏
  4. Spark 简介与安装部署
  5. 2020年中国基层医疗研究报告
  6. Xshell家庭版下载
  7. 微信小程序 731 天
  8. 50年间,高水平论文数量国家排名是怎样变化的?| 可视化数据
  9. linux 系统日志 驱动,linux下安装显卡驱动求救(内附安装日志文件)
  10. 立创EDA软件专业版 图示入门操作(全)
  11. 基于SSM的宠物领养系统(附源码)
  12. 【实用】MAC电脑如何进行截图,mac下QQ截图工具的用法
  13. 极客时间和极客学院_本周极客历史:旅行者指南,光盘和旋风式操作系统
  14. 南阳oj 58 bfs入门
  15. python列表索引超出范围 等于啥_Python列表错误,列表索引超出范围
  16. python批量查询ip归属地_python3.2批量查询IP地址区域
  17. 智慧安全3.0的融合之道
  18. 玩转华为数据中心交换机系列 | 配置MAC地址漂移检测示例
  19. Linux下烧写工具DNW和USB驱动安装
  20. android源码下载(下)

热门文章

  1. 项目中遇到Cannot read property 'length' of null
  2. Linux中查看正在使用的端口并强制删除占用端口
  3. stm32 str转hex_【SW4STM32生成 hex文件的设置方法】
  4. python使用函数的目的_python之函数基本使用
  5. linux操作系统的体系架构,linux操作系统的体系架构_linux操作系统的关机指令
  6. python为什么说csv文件不存在_如果CSV文件不存在,则如何创建它,然后仅将其追加到Python中...
  7. mysql command line client 目标不对_MySql轻松入门系列-第一站 从源码角度轻松认识mysql整体框架图...
  8. 实现redis 手动_Redis精华所在,一口气说完Redis的主从复制和哨兵模式
  9. ast.literal_eval
  10. 面试mysql慢查询_剑指Offer面试题:如何定位并优化慢查询sql