ReentrantLock

ReentrantLock,一个可重入的互斥锁,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

ReentrantLock基本用法

先来看一下ReentrantLock的基本用法:

public class ThreadDomain38
{private Lock lock = new ReentrantLock();public void testMethod(){try{lock.lock();for (int i = 0; i < 2; i++){System.out.println("ThreadName = " + Thread.currentThread().getName() + ", i  = " + i);}}finally{lock.unlock();}}
}

public class MyThread38 extends Thread
{private ThreadDomain38 td;public MyThread38(ThreadDomain38 td){this.td = td;}public void run(){td.testMethod();}
}

public static void main(String[] args)
{ThreadDomain38 td = new ThreadDomain38();MyThread38 mt0 = new MyThread38(td);MyThread38 mt1 = new MyThread38(td);MyThread38 mt2 = new MyThread38(td);mt0.start();mt1.start();mt2.start();
}

看一下运行结果:

ThreadName = Thread-1, i  = 0
ThreadName = Thread-1, i  = 1
ThreadName = Thread-0, i  = 0
ThreadName = Thread-0, i  = 1
ThreadName = Thread-2, i  = 0
ThreadName = Thread-2, i  = 1

没有任何的交替,数据都是分组打印的,说明了一个线程打印完毕之后下一个线程才可以获得锁去打印数据,这也证明了ReentrantLock具有加锁的功能

ReentrantLock持有的是对象监视器

前面已经证明了ReentrantLock具有加锁功能,但我们还不知道ReentrantLock持有的是什么锁,因此写个例子看一下:

public class ThreadDomain39
{private Lock lock = new ReentrantLock();public void methodA(){try{lock.lock();System.out.println("MethodA begin ThreadName = " + Thread.currentThread().getName());Thread.sleep(5000);System.out.println("MethodA end ThreadName = " + Thread.currentThread().getName());}catch (InterruptedException e){e.printStackTrace();}finally{lock.unlock();}}public void methodB(){lock.lock();System.out.println("MethodB begin ThreadName = " + Thread.currentThread().getName());System.out.println("MethodB begin ThreadName = " + Thread.currentThread().getName());lock.unlock();}
}

写两个线程分别调用methodA()和methodB()方法:

public class MyThread39_0 extends Thread
{private ThreadDomain39 td;public MyThread39_0(ThreadDomain39 td){this.td = td;}public void run(){td.methodA();}
}

public class MyThread39_1 extends Thread
{private ThreadDomain39 td;public MyThread39_1(ThreadDomain39 td){this.td = td;}public void run(){td.methodB();}
}

写一个main函数启动这两个线程:

public static void main(String[] args)
{ThreadDomain39 td = new ThreadDomain39();MyThread39_0 mt0 = new MyThread39_0(td);MyThread39_1 mt1 = new MyThread39_1(td);mt0.start();mt1.start();
}

看一下运行结果:

MethodB begin ThreadName = Thread-1
MethodB begin ThreadName = Thread-1
MethodA begin ThreadName = Thread-0
MethodA end ThreadName = Thread-0

看不见时间,不过第四确实是格了5秒左右才打印出来的。从结果来看,已经证明了ReentrantLock持有的是对象监视器,可以写一段代码进一步证明这一结论,即去掉methodB()内部和锁相关的代码,只留下两句打印语句:

MethodA begin ThreadName = Thread-0
MethodB begin ThreadName = Thread-1
MethodB begin ThreadName = Thread-1
MethodA end ThreadName = Thread-0

看到交替打印了,进一步证明了ReentrantLock持有的是"对象监视器"的结论。

不过注意一点,ReentrantLock虽然持有对象监视器,但是和synchronized持有的对象监视器不是一个意思,虽然我也不清楚两个持有的对象监视器有什么区别,不过把methodB()方法用synchronized修饰,methodA()不变,两个方法还是异步运行的,所以就记一个结论吧----ReentrantLock和synchronized持有的对象监视器不同

另外,千万别忘了,ReentrantLock持有的锁是需要手动去unlock()的

Condition

synchronized与wait()和nitofy()/notifyAll()方法相结合可以实现等待/通知模型,ReentrantLock同样可以,但是需要借助Condition,且Condition有更好的灵活性,具体体现在:

1、一个Lock里面可以创建多个Condition实例,实现多路通知

2、notify()方法进行通知时,被通知的线程时Java虚拟机随机选择的,但是ReentrantLock结合Condition可以实现有选择性地通知,这是非常重要的

看一下利用Condition实现等待/通知模型的最简单用法,下面的代码注意一下,await()和signal()之前,必须要先lock()获得锁,使用完毕在finally中unlock()释放锁,这和wait()/notify()/notifyAll()使用前必须先获得对象锁是一样的:

public class ThreadDomain40
{private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void await(){try{lock.lock();System.out.println("await时间为:" + System.currentTimeMillis());condition.await();System.out.println("await等待结束");}catch (InterruptedException e){e.printStackTrace();}finally{lock.unlock();}}public void signal(){try{lock.lock();System.out.println("signal时间为:" + System.currentTimeMillis());condition.signal();}finally{lock.unlock();}}
}

public class MyThread40 extends Thread
{private ThreadDomain40 td;public MyThread40(ThreadDomain40 td){this.td = td;}public void run(){td.await();}
}

public static void main(String[] args) throws Exception
{ThreadDomain40 td = new ThreadDomain40();MyThread40 mt = new MyThread40(td);mt.start();Thread.sleep(3000);td.signal();
}

看一下运行结果:

await时间为:1443970329524
signal时间为:1443970332524
await等待结束

差值是3000毫秒也就是3秒,符合代码预期,成功利用ReentrantLock的Condition实现了等待/通知模型。其实这个例子还证明了一点,Condition的await()方法是释放锁的,原因也很简单,要是await()方法不释放锁,那么signal()方法又怎么能调用到Condition的signal()方法呢?

注意要是用一个Condition的话,那么多个线程被该Condition给await()后,调用Condition的signalAll()方法唤醒的是所有的线程。如果想单独唤醒部分线程该怎么办呢?new出多个Condition就可以了,这样也有助于提升程序运行的效率。使用多个Condition的场景是很常见的,像ArrayBlockingQueue里就有。

转载于:https://www.cnblogs.com/xrq730/p/4855155.html

Java多线程11:ReentrantLock的使用和Condition相关推荐

  1. java多线程11.非阻塞同步机制

    关于非阻塞算法CAS. 比较并交换CAS:CAS包含了3个操作数---需要读写的内存位置V,进行比较的值A和拟写入的新值B.当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不 ...

  2. Java多线程系列---“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下: 01. Java多线程系列--"JUC锁"01之 框架 02. Java多线程系列--"JUC锁 ...

  3. Java多线程系列之“JUC集合“详解

    Java集合包 在"Java 集合系列01之 总体框架"中,介绍java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List( ...

  4. Java多线程(九)之ReentrantLock与Condition

    一.ReentrantLock 类 1.1 什么是reentrantlock java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java ...

  5. java多线程系列(四)---ReentrantLock的使用

    Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...

  6. Java多线程中使用ReentrantLock、synchronized加锁 简单举例

    Java多线程中使用ReentrantLock.synchronized加锁 简单举例 public class Demo {final static Lock lock = new Reentran ...

  7. Java多线程发展简史

    摘自: http://www.raychase.net/698 这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的Knowledge Sharing的一个整理,我希望能对Java从 ...

  8. Java总结篇系列:Java多线程(三)

    2019独角兽企业重金招聘Python工程师标准>>> 本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 public cla ...

  9. Java多线程 - AQS详解

    介绍 AQS是java.util.concurrent.locks下类AbstractQueuedSynchronizer的简称,是用于 通过Java源码来构建多线程的锁和同步器的一系列框架,用于Ja ...

最新文章

  1. 微信公众平台开发(104) 自定义菜单扫一扫、发图片、发地理位置
  2. 大数据时代企业如何保障数据安全?这款工具值得一看
  3. 计算机鼠标不好使,鼠标不好用 原因竟然让人哭笑不得
  4. Intellij idea导入项目时没有目录结构
  5. 物理服务器备份系统,物理备份和逻辑备份区别
  6. jsp压缩html,使用HtmlCompressor压缩JSP编译的Html代码
  7. Java跳出多重循环
  8. php鼠标点击图片后换图片,鼠标滑过改变图片
  9. 初步使用计算机学设计,幼儿园计算机教学设计参考
  10. 云端点保护解决方案行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  11. 手机上有没有学python的软件-有哪些可以在手机上敲Python代码的App
  12. linux系统如何启用安全内核,安全 - Linux 内核引导选项简介
  13. java 典型程序,13道Java典型的Java小程序
  14. Java实现微信小程序登录(服务端)
  15. 系统服务器iis如何启动不了,win7系统iis启动不了的详细解决步骤
  16. 手机如何打开html文件怎么打开,怎么在手机上打开HTML文件怎么打开
  17. cosx sinx 泰勒展开 C++
  18. javascript中this和super用法
  19. 不是python文件打开的合法模式组合是_以下选项中,不是Python文件打开的合法模式组合是:...
  20. Android封装含有通用标题栏的基类BaseActivity

热门文章

  1. Python图片攻击
  2. python中sorted()函数的用法_Python中的Sorted()函数
  3. WIN7部分程序中文乱码的简单解决方法
  4. NC / Netcat - 文件传输
  5. oracle中时间、日期函数的总结
  6. Android开发:Menu选项菜单
  7. fedora下做成liveOS的U盘容量变小问题
  8. (转)关于两次fork
  9. as5.4安装gcc和g++
  10. 显示文字_如何观看HBO Max并显示中文字幕?