- 浏览: 491638 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
herofighter2008:
图呢?图呢?图呢?图呢?
BlockingQueue -
zy13608089849:
请问一下博主,文中几处提到的图,怎么都没有?是我这显示不出来还 ...
BlockingQueue -
swift911:
在短信的场景下很好用,感谢分享
BlockingQueue -
tony_0529:
学习了~谢谢分享。
BlockingQueue -
Master-Gao:
...
BlockingQueue
一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之……
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个
线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这
个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是
ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己
(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考
下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)
这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下:
- public class Buffer {
- private Object lock;
- public Buffer() {
- lock = this ;
- }
- public void write() {
- synchronized (lock) {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…" );
- for (;;) // 模拟要处理很长时间
- {
- if (System.currentTimeMillis()
- - startTime > Integer.MAX_VALUE)
- break ;
- }
- System.out.println("终于写完了" );
- }
- }
- public void read() {
- synchronized (lock) {
- System.out.println("从这个buff读数据" );
- }
- }
- }
接着,我们来定义2个线程,一个线程去写,一个线程去读。
- public class Writer extends Thread {
- private Buffer buff;
- public Writer(Buffer buff) {
- this .buff = buff;
- }
- @Override
- public void run() {
- buff.write();
- }
- }
- public class Reader extends Thread {
- private Buffer buff;
- public Reader(Buffer buff) {
- this .buff = buff;
- }
- @Override
- public void run() {
- buff.read();//这里估计会一直阻塞
- System.out.println("读结束" );
- }
- }
好了,写一个Main来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。
- public class Test {
- public static void main(String[] args) {
- Buffer buff = new Buffer();
- final Writer writer = new Writer(buff);
- final Reader reader = new Reader(buff);
- writer.start();
- reader.start();
- new Thread( new Runnable() {
- @Override
- public void run() {
- long start = System.currentTimeMillis();
- for (;;) {
- //等5秒钟去中断读
- if (System.currentTimeMillis()
- - start > 5000 ) {
- System.out.println("不等了,尝试中断" );
- reader.interrupt();
- break ;
- }
- }
- }
- }).start();
- }
- }
我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,就一直开始等待了,就算它等死,也得不到锁,因为写线程要
21亿秒才能完成 T_T
,即使我们中断它,它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃
对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
- import java.util.concurrent.locks.ReentrantLock;
- public class BufferInterruptibly {
- private ReentrantLock lock = new ReentrantLock();
- public void write() {
- lock.lock();
- try {
- long startTime = System.currentTimeMillis();
- System.out.println("开始往这个buff写入数据…" );
- for (;;) // 模拟要处理很长时间
- {
- if (System.currentTimeMillis()
- - startTime > Integer.MAX_VALUE)
- break ;
- }
- System.out.println("终于写完了" );
- } finally {
- lock.unlock();
- }
- }
- public void read() throws InterruptedException {
- lock.lockInterruptibly();// 注意这里,可以响应中断
- try {
- System.out.println("从这个buff读数据" );
- } finally {
- lock.unlock();
- }
- }
- }
当然,要对reader和writer做响应的修改
- public class Reader extends Thread {
- private BufferInterruptibly buff;
- public Reader(BufferInterruptibly buff) {
- this .buff = buff;
- }
- @Override
- public void run() {
- try {
- buff.read();//可以收到中断的异常,从而有效退出
- } catch (InterruptedException e) {
- System.out.println("我不读了" );
- }
- System.out.println("读结束" );
- }
- }
- /**
- * Writer倒不用怎么改动
- */
- public class Writer extends Thread {
- private BufferInterruptibly buff;
- public Writer(BufferInterruptibly buff) {
- this .buff = buff;
- }
- @Override
- public void run() {
- buff.write();
- }
- }
- public class Test {
- public static void main(String[] args) {
- BufferInterruptibly buff = new BufferInterruptibly();
- final Writer writer = new Writer(buff);
- final Reader reader = new Reader(buff);
- writer.start();
- reader.start();
- new Thread( new Runnable() {
- @Override
- public void run() {
- long start = System.currentTimeMillis();
- for (;;) {
- if (System.currentTimeMillis()
- - start > 5000 ) {
- System.out.println("不等了,尝试中断" );
- reader.interrupt();
- break ;
- }
- }
- }
- }).start();
- }
- }
这次“读”线程接收到了lock.lockInterruptibly()中断,并且有效处理了这个“异常”。好奇的读者,肯定要探个究竟,为什么ReentrantLock能做到这点,接下来,我们去迷宫探险吧……
发表评论
-
HashMap的非线程安全
2013-11-25 16:06 878在平时开发中,我们经常采用HashMap来作为本地缓存的一种 ... -
SynchronousQueue
2012-08-11 23:30 13238SynchronousQueue是这样一种阻塞队列,其中每个 ... -
(转)ThreadPoolExecutor
2012-08-11 22:41 1267一、ThreadPoolExecutor使 ... -
Java Atomic
2012-05-09 21:13 4162我们知道volatile修饰的变量可以实现基本的加载和赋值的原 ... -
ArrayList线程不安全分析
2012-04-22 17:49 8580一个 ArrayList ,在添加一个元素的时候,它可能会有两 ... -
ConcurrentModificationException
2012-04-22 16:38 1289如果在获得了某个集合的迭代器之后,除了通过这个迭代器之外对该集 ... -
LinkedBlockingQueue和ConcurrentLinkedQueue
2012-04-21 14:19 80041.LinkedBlockingQueue<E>: ... -
ReentrantLock和synchronized的区别随笔
2012-04-20 20:27 2413可重入锁 ReentrantLock 的含义是: ... -
(转)ReentrantLock和synchronized两种锁定机制的对比
2012-04-20 20:07 1004多线程和并发性并不是什么新内容,但是 Java 语言设计中的创 ... -
volatile变量
2012-02-20 21:26 1786我们知道,在Java中设置变量值的操作,除了long和doub ... -
(转)java并发编程-Executor框架
2012-01-17 09:42 976Executor框架是指java 5中引入的一系列并发库中 ... -
ThreadLocal的几种误区
2011-11-05 22:54 906最近由于需要用到ThreadLocal,在网上搜索 ... -
正确理解ThreadLocal
2011-11-05 22:41 1275首先, ThreadLocal 不是用来解决 ...
相关推荐
ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重...
ReentrantLock ...ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。 3.synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。
ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。下面我们来深入了解一下它吧
今天小编就为大家分享一篇关于Java源码解析之可重入锁ReentrantLock,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
重入锁ReentrantLock 相对来说是synchronized、Object.wait()和Object.notify()方法的替代品(或者说是增强版),在JDK5.0的早期版本,重入锁的性能远远好于synchronized,但从JDK6.0开始,JDK在synchronized上做了...
主要介绍了Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁,本文讲解了ReentrantLock概况、Lock接口、Lock使用、轮询锁的和定时锁、公平性、可中断获锁获取操作等内容,需要的朋友可以参考下
1、ReentrantLock简介 2、ReentrantLock函数列表 3、重入的实现 4、公平锁与非公平锁 5、ReentrantLock 扩展的功能 6
公平和非公平选择这里提到一个锁获取的公平性问题,如果在绝对时间上,先对锁进行获取的请求一定先被满足,那么这个锁是公平的,反之,是不公平的。public void
解释为什么它被称为“可重入锁”,以及如何解决传统锁可能的问题。 ReentrantLock 的基本用法: 深入探讨如何使用 ReentrantLock 来保护共享资源。演示如何通过 lock 和 unlock 方法来实现线程的同步和互斥。 ...
7、深入理解 AQS 独占锁之 Reentrantlock 源码分析 (1).pdf 8、读写锁ReentrantReadWriteLock&StampLock详解.pdf 9、并发容器 (Map、List、Set) 实战及其原理.pdf 10、阻塞队列BlockingQueue 实战及其原理分析.pdf
java中的乐观锁与悲观锁,synchronized与ReentrantLock重入锁的说明与比较
从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些。 场景1:如果发现该操作已经在执行中则不再执行(有状态执行) a、用在定时任务时,如果任务执行时间可能超过下次计划执行时间,...
主要介绍了java并发之重入锁-ReentrantLock,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
带你看看Javad的锁-ReentrantLock前言ReentrantLock简介Synchronized对比用法源码分析代码结构方法分析SyncNonfairSyncFairSync非公平锁VS公平锁什么是公平非公平ReentrantLockReentrantLock的构造函数lock加锁方法...
主要介绍了ReentrantLock源码之条件锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习一下吧
ReentrantLock源码剖析
主要介绍了Java多线程 ReentrantLock互斥锁详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
java语言 并发编程 ReentrantLock与synchronized区别 详解
private static class MyReentrantLock extends ReentrantLock {public MyReentrantLo