`
talentluke
  • 浏览: 592250 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

深入研究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原语来加锁,如下:

Java代码
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个线程,一个线程去写,一个线程去读。

Java代码
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来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。

Java代码
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吧,可中断缓存。

Java代码
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做响应的修改

Java代码
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();  
    }   
}  

分享到:
评论

相关推荐

    教你完全理解ReentrantLock重入锁

    ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重...

    java ReentrantLock详解.docx

    ReentrantLock ...ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。 3.synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

    ReentrantLock源码详解--公平锁、非公平锁

    ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。下面我们来深入了解一下它吧

    Java中ReentrantLock的使用.docx

    重入锁ReentrantLock 相对来说是synchronized、Object.wait()和Object.notify()方法的替代品(或者说是增强版),在JDK5.0的早期版本,重入锁的性能远远好于synchronized,但从JDK6.0开始,JDK在synchronized上做了...

    Java源码解析之可重入锁ReentrantLock

    今天小编就为大家分享一篇关于Java源码解析之可重入锁ReentrantLock,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    java并发锁面试知识

    java中的乐观锁与悲观锁,synchronized与ReentrantLock重入锁的说明与比较

    jnpr-eychen#jun_ppt#锁-重入锁(ReentrantLock)1

    公平和非公平选择这里提到一个锁获取的公平性问题,如果在绝对时间上,先对锁进行获取的请求一定先被满足,那么这个锁是公平的,反之,是不公平的。public void

    Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁

    主要介绍了Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁,本文讲解了ReentrantLock概况、Lock接口、Lock使用、轮询锁的和定时锁、公平性、可中断获锁获取操作等内容,需要的朋友可以参考下

    locks框架_ReentrantLock.pdf

    解释为什么它被称为“可重入锁”,以及如何解决传统锁可能的问题。 ReentrantLock 的基本用法: 深入探讨如何使用 ReentrantLock 来保护共享资源。演示如何通过 lock 和 unlock 方法来实现线程的同步和互斥。 ...

    Java重入锁ReentrantLock

     从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些。  场景1:如果发现该操作已经在执行中则不再执行(有状态执行)  a、用在定时任务时,如果任务执行时间可能超过下次计划执行时间,...

    Java多线程之ReentrantLock与Condition - 平凡希 - 博客园1

    1、ReentrantLock简介 2、ReentrantLock函数列表 3、重入的实现 4、公平锁与非公平锁 5、ReentrantLock 扩展的功能 6

    ReentrantLock源码详解--条件锁

    主要介绍了ReentrantLock源码之条件锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习一下吧

    详解java并发之重入锁-ReentrantLock

    主要介绍了java并发之重入锁-ReentrantLock,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    Java多线程 ReentrantLock互斥锁详解

    主要介绍了Java多线程 ReentrantLock互斥锁详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    多线程(11)ReentrantLock公平锁与非公平锁(修改)1

    private static class MyReentrantLock extends ReentrantLock {public MyReentrantLo

    7、深入理解AQS独占锁之ReentrantLock源码分析(1).pdf

    7、深入理解 AQS 独占锁之 Reentrantlock 源码分析 (1).pdf 8、读写锁ReentrantReadWriteLock&StampLock详解.pdf 9、并发容器 (Map、List、Set) 实战及其原理.pdf 10、阻塞队列BlockingQueue 实战及其原理分析.pdf

    Java中的ReentrantLock类最全讲义

    目录: 简介 ReentrantLock的基本用法 2.1 创建ReentrantLock 2.2 获取锁和释放锁 公平性与非公平性 3.1 公平锁 3.2 非公平锁 ...可重入性 ReentrantLock与synchronized的对比 最佳实践与注意事项

    ReentrantLock与synchronized区别

    java语言 并发编程 ReentrantLock与synchronized区别 详解

    JUC知识点总结(三)ReentrantLock与ReentrantReadWriteLock源码解析

    8. Lock接口 (ReentrantLock 可重入锁) 特性 ReentantLock 继承接口 Lock 并实现了接口中定义的方法, 它是一种可重入锁, 除了能完成 synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁...

Global site tag (gtag.js) - Google Analytics