java中ReentrantLock彻底解决并发线程的无限等待

ReentrantLock彻底解决并发线程的无限等待

马 克-to-win:上面的例子,只能做到根据请求Synchronized方法的队列里的线程的数量,决定我是否进入队列等待。但是一旦决定了等待,进入 了等待队列以后,就无法退出队列。想达到这个效果,必须要用到ReentrantLock的技术。ReentrantLock翻译成中文就是可重入锁。下 面这段话比较难,新手可忽略。和可重入锁相对的就是不可重入锁,又名自旋锁。为什么叫不可重入锁?因为一旦进入一个带锁的方法,你在这个方法当中,如果想 再进入另外一个带锁的方法,就进不去了,好像自己给自己上了锁(自旋)因为你在第一个方法当中你还没有解开锁。而可重入锁在判断中加了一条是不是本个线 程?如是,就随便进入当前对象所有带锁的方法。如果对我以上这段话,老手也是不理解的话,可参考我参考目录中的一个参考网页。注意sun公司的 ReentrantLock是个类,而sun公司的Lock是个接口。所以为求简单,我们的例子中就用ReentrantLock, ReentrantLock就是为了解决 Synchronized技术的很多弊病而生的。缺点就是使用复杂,简单问题还用 Synchronized就挺好。马克-to-win:因为ReentrantLock类中的lockInterruptibly();方法能够让正在想 获得锁的线程被其他线程中断(见下例),从而打消原来要获得锁的计划。当然如果没有其他的线程占有锁的话,lockInterruptibly();方法 也可以让当 前线程从容获得锁。

另外底下的例子有点需要注意,lock.lockInterruptibly();的方法的catch部分要放 在上一级的方法调用 中。马克-to-win:换句话说,就故意让它在被打断时在本级方法中崩溃,回到上一级。否则的话,如果本级方法能够优雅的执行完,执行到 lock.unlock();就会出现问题。(Exception in thread java.lang.IllegalMonitorStateException,报完这个exception后,会在lock.unlock()这句话 直接崩溃不能优雅结束)因为锁已经被打断怎么还能unlock呢?另外注意正常的锁的lock.unlock别忘了必须执行。否则程 序的锁的状态 (lock hold count)就错了。lockInterruptibly():Acquires the lock if it is not held by another thread and returns immediately, setting the lock hold count to one. If the current thread already holds this lock then the hold count is incremented by one and the method returns immediately.  

例1.9.7:(本例模仿七个人想排队,但后来两个人主动放弃排队,自己打断自己。)

import java.util.concurrent.locks.ReentrantLock;
class A {
    private ReentrantLock lock = new ReentrantLock();
    int ticketNum = 10;
    public void buyOne() throws InterruptedException {
        System.out.println("just before lock.lockInterruptibly();");
/*lock.lockInterruptibly();的意思就是,当前线程获取了一把可打断的锁。当有n个thread同时执行到这句时,只有第一个thread能获得这个lock,其他thread都必须挡在那,在后边排队。catch 不能放在本级方法调用中,否则当lock被打断后,继续优雅执行,lock.unlock();被执行时,就会出现lock状态不对的问题 (Exception in thread  java.lang.IllegalMonitorStateException,报完这个exception后,会在lock.unlock()这句话 直接崩溃不能优雅结束),因为lock已经被打断了。换句话说,lock一旦被打断,必须确保lock.unlock()不能被执行。*/
        lock.lockInterruptibly();
        System.out.println(Thread.currentThread().getName() + "ticketNum is"
                + ticketNum);
        if (ticketNum > 0) {
            ticketNum--;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("模仿select * from table for update,执行的很慢,买了一张"
                    + Thread.currentThread().getName() + "ticketNum is"
                    + ticketNum);
        }
        lock.unlock();//释放锁
    }

版权保护原文出处:http://www.mark-to-win.com/index.html?content=JavaBeginner/javaUrl.html&chapter=JavaBeginner/JavaBeginner6_web.html#ReentrantLockSolveInfinateWaitlockInterruptiblyUsage

猜你喜欢

转载自blog.csdn.net/mark_to_win/article/details/89285181