注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

互斥锁ReentrantLock  

2010-09-24 16:47:43|  分类: JAVA线程安全 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
public class ReentrantLock
extends Object
implements Lock, Serializable
一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大
ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,
调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。
可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,
这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。
与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),
但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。
因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。
还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
建议总是 立即实践,使用 lock 块来调用 try,在之前/之后的构造中,最典型的代码如下:
 class {
   private final ReentrantLock lock = new ReentrantLock();
   // ...
   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }
 
除了实现 Lock 接口,此类还定义了 isLocked 和 getLockQueueLength 方法,以及一些相关的 protected 访问方法,
这些方法对检测和监视可能很有用。
该类的序列化与内置锁的行为方式相同:一个反序列化的锁处于解除锁定状态,不管它被序列化时的状态是怎样的。
此锁最多支持同一个线程发起的 2147483648 个递归锁。试图超过此限制会导致由锁方法抛出的 Error。 
注意1:此类的构造方法接受一个可选的公平参数。当设置为 true 时,在多个线程的争用下,
这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。但是公平锁不能保证线程调度的公平性。
因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会。
注意2:此锁是个递归锁。此锁最多支持同一个线程发起的 2147483648 个递归锁。关于递归锁的问题可参照《可递归锁与非递归锁》
主要函数
public void lock()
    获取锁。
    如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
    如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
    如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。
    指定者:
        接口 Lock 中的 lock
注意1:"如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
        如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。"
        这样就实现了递归锁.
public void lockInterruptibly()
                       throws InterruptedException

    如果当前线程未被中断,则获取锁。
    如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
    如果当前线程已经保持此锁,则将保持计数加 1,并且该方法立即返回。
    如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
        * 锁由当前线程获得;或者
        * 其他某个线程中断当前线程。 
    如果当前线程获得该锁,则将锁保持计数设置为 1。
    如果当前线程:
        * 在进入此方法时已经设置了该线程的中断状态;或者
        * 在等待获取锁的同时被中断。 
    则抛出 InterruptedException,并且清除当前线程的已中断状态。
    在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取。
    指定者:
        接口 Lock 中的 lockInterruptibly
    抛出:
        InterruptedException - 如果当前线程已中断。
注意:它会抛出InterruptedException。
        关于InterruptedException更多知识请参阅《JAVA线程的interrupt》。
public boolean tryLock()
    仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
    如果该锁没有被另一个线程保持,并且立即返回 true 值,则将锁的保持计数设置为 1。
    即使已将此锁设置为使用公平排序策略,但是调用 tryLock() 仍将 立即获取锁(如果有可用的),
    而不管其他线程当前是否正在等待该锁。在某些情况下,此“闯入”行为可能很有用,即使它会打破公平性也如此。
    如果希望遵守此锁的公平设置,则使用 tryLock(0, TimeUnit.SECONDS) ,它几乎是等效的(也检测中断)。
    如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true。
    如果锁被另一个线程保持,则此方法将立即返回 false 值。
    指定者:
        接口 Lock 中的 tryLock
    返回:
        如果锁是自由的并且被当前线程获取,或者当前线程已经保持该锁,则返回 true;否则返回 false
注意1:该方法不会阻塞,它也不一定能得到锁。如果得到返回ture,否则false.
注意2:即使已将此锁设置为使用公平排序策略,但是调用 tryLock() 仍将 立即获取锁(如果有可用的),
    而不管其他线程当前是否正在等待该锁。这样看来他获得锁的优先级比正被阻塞的lock()方法高。
public boolean tryLock(long timeout,
                       TimeUnit unit)
                throws InterruptedException
    如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
    如果该锁没有被另一个线程保持,并且立即返回 true 值,则将锁的保持计数设置为 1。
    如果为了使用公平的排序策略,已经设置此锁,并且其他线程都在等待该锁,则不会 获取一个可用的锁。
    这与 tryLock() 方法相反。如果想使用一个允许闯入公平锁的定时 tryLock,那么可以将定时形式和不定时形式组合在一起:
    if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }  
    如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true。
    如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下三种情况之一以前,该线程将一直处于休眠状态:
        * 锁由当前线程获得;或者
        * 其他某个线程中断 当前线程;或者
        * 已超过指定的等待时间 
    如果获得该锁,则返回 true 值,并将锁保持计数设置为 1。
    如果当前线程:
        * 在进入此方法时已经设置了该线程的中断状态;或者
        * 在等待获取锁的同时被中断。 
    则抛出 InterruptedException,并且清除当前线程的已中断状态。
    如果超出了指定的等待时间,则返回值为 false。如果该时间小于等于 0,则此方法根本不会等待。
    在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取,或者报告所用的等待时间。
    指定者:
        接口 Lock 中的 tryLock
    参数:
        timeout - 等待锁的时间
        unit - timeout 参数的时间单位 
    返回:
        如果锁是自由的并且由当前线程获取,或者当前线程已经保持该锁,则返回 true;如果在获取该锁之前已经到达等待时间,则返回 false 
    抛出:
        InterruptedException - 如果当前线程被中断 
        NullPointerException - 如果时间单位为 null
注意1:如果为了使用公平的排序策略,已经设置此锁,并且其他线程都在等待该锁,
            则不会 获取一个可用的锁。这与 tryLock() 方法相反
注意2:它会抛出InterruptedException。
        关于InterruptedException更多知识请参阅《JAVA线程的interrupt》。
public void unlock()
    试图释放此锁。
    如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。
    如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException。
    指定者:
        接口 Lock 中的 unlock
    抛出:
        IllegalMonitorStateException - 如果当前线程没有保持此锁
注意1:"如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。"  这样就实现了递归锁.
下面两个是对于调试和测试很有用的方法
public int getHoldCount()
    查询当前线程保持此锁的次数。
    对于与解除锁操作不匹配的每个锁操作,线程都会保持一个锁。
    保持计数信息通常只用于测试和调试。例如,如果不应该使用已经保持的锁进入代码的某一部分,则可以声明如下:
     class X {
       ReentrantLock lock = new ReentrantLock();
    
   // ...     
       
public void m() { 
         assert lock.getHoldCount() == 0;
         lock.lock();
         
try {
           
// ... method body
         } finally {
           lock.unlock();
         }
       }
     }
    返回:
        当前线程保持此锁的次数,如果此锁未被当前线程保持过,则返回 0

public boolean isHeldByCurrentThread()
    查询当前线程是否保持此锁。
    与内置监视器锁的 Thread.holdsLock(java.lang.Object) 方法类似,此方法通常用于调试和测试。
    例如,只在保持某个锁时才应调用的方法可以声明如下:
     class X {
       ReentrantLock lock = new ReentrantLock();
       // ...
       public void m() { 
           assert lock.isHeldByCurrentThread();
           // ... method body
       }
     }
    还可以用此方法来确保某个重入锁是否以非重入方式使用的,例如:
     class X {
       ReentrantLock lock = new ReentrantLock();
    
   // ...

       public void m() { 
           assert !lock.isHeldByCurrentThread();
           lock.lock();
           try {
               // ... method body
           } finally {
               lock.unlock();
           }
       }
     }
    返回:
        如果当前线程保持此锁,则返回 true;否则返回 false
public Condition newCondition()
    返回用来与此 Lock 实例一起使用的 Condition 实例。
    在使用内置监视器锁时,返回的 Condition 实例支持与 Object 的监视器方法(wait、notify 和 notifyAll)相同的用法。
        * 在调用 Condition、waiting 或 signalling 这些方法中的任意一个方法时,如果没有保持此锁,则将抛出 IllegalMonitorStateException。
        * 在调用 waiting 条件方法时,将释放锁,并在这些方法返回之前,重新获取该锁,将锁保持计数恢复为调用方法时所持有的值。
        * 如果线程在等待时被中断,则等待将终止,并将抛出 InterruptedException,清除线程的中断状态。
        * 等待线程按 FIFO 顺序收到信号。
        * 等待方法返回的线程重新获取锁的顺序与线程最初获取锁的顺序相同,在默认情况下,未指定此顺序,但对于公平 锁,它们更倾向于那些等待时间最长的线程。 
    指定者:
        接口 Lock 中的 newCondition
    返回:
        Condition 对象
注意:关于Condition的更多知识和使用请参阅《Condition》。
Lock的使用很简单,见实例1。关于Lock的Condition使用请查阅《Condition
实例1:
    static void LockDemo()
    {
        Counter counter=new Counter();
        System.out.println("init value:"+counter.getValue());
        counter.increment();
        System.out.println("the value:"+counter.getValue());
        counter.decrement();
        counter.decrement();
        counter.decrement();
        System.out.println("the value:"+counter.getValue());
    }
}
class Counter {
    private int value;
    private final ReentrantLock lock = new ReentrantLock();
    public int getValue() 
    {
        lock.lock();
        try{
        return value; 
        }finally
        {
            lock.unlock();
            System.out.println("the hode count of lock is:"+lock.getHoldCount());
        }
    }
    public int increment() 
    { 
        lock.lock();
        try{
        return ++value; 
        }finally
        {
            lock.unlock();
        }
    }
    public int decrement() {         
        lock.lock();
        try{
            return --value; 
        }finally
        {
            lock.unlock();
        }
    }
}
  评论这张
 
阅读(1120)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017