可重入锁:ReentrantLock理解使用
(一)可重入性
可重入性描述这样的一个问题:一个线程在持有一个锁的时候,它内部能否再次(多次)申请该锁。如果一个线程已经获得了锁,其内部还可以多次申请该锁成功。那么我们就称该锁为可重入锁。通过以下伪代码说明:
void methodA(){
lock.lock(); // 获取锁
methodB();
lock.unlock() // 释放锁
} void methodB(){
lock.lock(); // 获取锁
// 其他业务
lock.unlock();// 释放锁
}
public class ReentrantLockDemo01 implements Runnable { private Lock lock = new ReentrantLock(); private int tickets = 200; @Override
public void run() {
while (true) {
lock.lock(); // 获取锁
try {
if (tickets > 0) {
TimeUnit.MILLISECONDS.sleep(100);
System.out.println(Thread.currentThread().getName() + " " + tickets--);
} else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放所
}
}
} public static void main(String[] args) {
ReentrantLockDemo01 reentrantLockDemo = new ReentrantLockDemo01();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(reentrantLockDemo, "thread" + i);
thread.start();
}
}
}
2.2.2 lockInterruptibly()方法说明
从Lock的源码可以看出:lockInterruptibly() 抛出中断异常
void lockInterruptibly() throws InterruptedException;
在synchronize关键字中,同步代码块发送阻塞的情况,例如:wait(),sleep(),jion()等情况下,可以被中断。中断并不意味着线程已经终止
代码示例如下:
public class ReentrantLockDemo02 implements Runnable { private Lock lock = new ReentrantLock(); @Override
public void run() {
try {
lock.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + " running");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " finished");
lock.unlock();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " interrupted");
}
} public static void main(String[] args) {
ReentrantLockDemo02 reentrantLockDemo = new ReentrantLockDemo02();
Thread thread01 = new Thread(reentrantLockDemo, "thread01");
Thread thread02 = new Thread(reentrantLockDemo, "thread02");
thread01.start();
thread02.start();
thread02.interrupt();
}
}
输出结果:
thread01 running
thread02 interrupted
thread01 finished
public class ReentrantLockDemo03 implements Runnable { private ReentrantLock lock = new ReentrantLock(); @Override
public void run() {
try {
if (lock.tryLock(2, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + " 获取当前lock锁");
TimeUnit.SECONDS.sleep(4);
} else {
System.out.println(Thread.currentThread().getName()+ " 获取锁失败");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} public static void main(String[] args) {
ReentrantLockDemo03 reentrantLockDemo = new ReentrantLockDemo03();
Thread thread01 = new Thread(reentrantLockDemo, "thread01");
Thread thread02 = new Thread(reentrantLockDemo, "thread02");
thread01.start();
thread02.start();
}
}
Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。
public class ProducerConsumerTest { private Lock lock = new ReentrantLock(); private Condition addCondition = lock.newCondition(); private Condition removeCondition = lock.newCondition(); private LinkedList<Integer> resources = new LinkedList<>(); private int maxSize; public ProducerConsumerTest(int maxSize) {
this.maxSize = maxSize;
} public class Producer implements Runnable { private int proSize; private Producer(int proSize) {
this.proSize = proSize;
} @Override
public void run() {
lock.lock();
try {
for (int i = 1; i < proSize; i++) {
while (resources.size() >= maxSize) {
System.out.println("当前仓库已满,等待消费...");
try {
addCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("已经生产产品数: " + i + "\t现仓储量总量:" + resources.size());
resources.add(i);
removeCondition.signal();
}
} finally {
lock.unlock();
} }
} public class Consumer implements Runnable { @Override
public void run() {
String threadName = Thread.currentThread().getName();
while (true) {
lock.lock();
try {
while (resources.size() <= 0) {
System.out.println(threadName + " 当前仓库没有产品,请稍等...");
try {
// 进入阻塞状态
removeCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费数据
int size = resources.size();
for (int i = 0; i < size; i++) {
Integer remove = resources.remove();
System.out.println(threadName + " 当前消费产品编号为:" + remove);
}
// 唤醒生产者
addCondition.signal();
} finally {
lock.unlock();
}
} }
} public static void main(String[] args) throws InterruptedException {
ProducerConsumerTest producerConsumerTest = new ProducerConsumerTest(10);
Producer producer = producerConsumerTest.new Producer(100);
Consumer consumer = producerConsumerTest.new Consumer();
final Thread producerThread = new Thread(producer, "producer");
final Thread consumerThread = new Thread(consumer, "consumer");
producerThread.start();
TimeUnit.SECONDS.sleep(2);
consumerThread.start();
}
}
我这儿整理了比较全面的JAVA相关的面试资料,
需要领取面试资料的同学,请加群:473984645
可重入锁:ReentrantLock理解使用的更多相关文章
- Java 重入锁 ReentrantLock 原理分析
1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...
- 轻松学习java可重入锁(ReentrantLock)的实现原理
转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...
- java 可重入锁ReentrantLock的介绍
一个小例子帮助理解(我们常用的synchronized也是可重入锁) 话说从前有一个村子,在这个村子中有一口水井,家家户户都需要到这口井里打水喝.由于井水有限,大家只能依次打水.为了实现家家有水喝,户 ...
- 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)
前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...
- 多线程通信的两种方式? (可重入锁ReentrantLock和Object)
(一)Java中线程协作的最常见的两种方式: (1)利用Object的wait().notify()和notifyAll()方法及synchronized (2)使用Condition.Reentra ...
- synchronized关键字,Lock接口以及可重入锁ReentrantLock
多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...
- 17_重入锁ReentrantLock
[概述] 重入锁可以完全代替synchronized关键字. 与synchronized相比,重入锁ReentrantLock有着显示的操作过程,即开发人员必须手动指定何时加锁,何时释放锁,所以重入锁 ...
- Java 显示锁 之 重入锁 ReentrantLock(七)
ReentrantLock 重入锁简介 重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁.另外,该锁还支持获取锁时的公平与非公平性的选择. 重入锁 ReentrantL ...
- ReentrantLock可重入锁的理解和源码简单分析
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...
- Java中可重入锁ReentrantLock原理剖析
本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQue ...
随机推荐
- fiddler接口知识
1. 访问接口时经常会出现乱码的情况,需要fiddler解码操作 2.域名过滤
- jumpserver4.0centos7安装步骤
一步一步安装(CentOS) 测试推荐环境 CPU: 64位双核处理器 内存: 4G DDR3 数据库:mysql 版本大于等于 5.6 mariadb 版本大于等于 5.5.6 环境 系统: Cen ...
- [FW]使用kprobes查看内核内部信息
使用printk打印变量等方法,是调试内核的有效方法之一,但是这种方法必须重新构建并用新内核启动,调试效率比较低.以内核模块的方式使用kprobes.jprobes,就可以在任意地址插入侦测器,执行包 ...
- POJ 3020:Antenna Placement(无向二分图的最小路径覆盖)
Antenna Placement Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6334 Accepted: 3125 ...
- LVS _keepalived 配置
#!/bin/bash HOSTNAME=$(HOSTNAME) ETHNAME=ens34 ID=-]{,}\.[-]{,}\.[-]{,}\.[-]{,}" | awk -F . 'NR ...
- java CountDownLatch、CyclicBarrier和 Semaphore用法
一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent中包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之 ...
- 记录Angular2.0学习遇到的问题
最近开始学习Angular2.0,准备持续记录下踩过得坑 1如何读取本地json文件: 需要通过http请求读取本地json文件,数据文件要放在assets文件夹下面 Service中的代码如下: ...
- vector<类指针>清理
https://www.cnblogs.com/nanke/archive/2011/05/10/2042662.html 1.vector<class> &aa,作为函数参数 2 ...
- HBase性能优化方法总结(三):读表操作(转)
转自:http://www.cnblogs.com/panfeng412/archive/2012/03/08/hbase-performance-tuning-section3.html 本文主要是 ...
- mongodb C#连接报错 Invalid credentials for database 'admin'
这2天学习mongodb3.2.9,用户设置好了,结果用C#查询的时候报错了,看字面意思是用户验证没通过,但是我用shell是完全没有问题的,后来网上搜了下,发现原来是我用的是旧驱动,旧驱动用的是旧的 ...