code_money_guji's Blog

Happy coding

ReentantLock

code_money_guji posted @ 2011年2月23日 01:08 in Concurrency in java , 1684 阅读

参考资料:

        1 java 并发实践

        2 JDK 文档以及源代码

Reentantlock在jdk文档中的介绍如下:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

其完成了java synchorized的语义.

此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。

上述事例中,涉及到经常使用的ReentrantLock的方法, lock()和unlock().

其外, ReentantLock 提供了Condition的相关操作.

ConditionObject 监视器方法( wait,notify和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)

Condition Exsample [from JDK api --- Condition]

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }

                           示例代码 2

针对上面的例子, 如下说明:

1 在调用lock.await()的时候,必须获取lock的锁定(而不是简单的synchronized(notEmpty)). 否则会抛出异常:

  java.lang.IllegalMonitorStateException 注意了, 当使用Object中的wait()和signal()或者signalAll()时,一定要确保已经获取了监视对象的锁定. 如下代码就是错的:

 synchronized(someObject){

                  await();// 错误,这里的await需要锁定this 而不是object可以改为someObject.wait()

                  //signal()同上.

                   ...

}

 

2 condiionObject.await()必须出现在while(condition)中, 原因有:

  2.1 防止虚假唤醒;

  2.2 解释代码为【示例代码2】中的while改为if, get方法的notFull.signal()改为notFull.signalAll()

如果有N个线程在notFull这个Condition对象的wait-set中等待【put操作中】, 只有一个活跃线程调用这个condition对象的notifyAll方法, 即是在take操作中的notFull.signal()误写为notFull.signalAll(); 那么,N个线程会同步,依次执行

items[putptr] = x;

假设这个时候putptr已经是MAX_SIZE -2, 线程数N > 2; 那么会抛出相关的越界异常;

  上述的的解释可能会比较“不现实”. 但是, while语句的作用就是强制N个等待线程在某种原因唤醒的时候, 依然能够检查等待条件.

 

3 signal的操作会等待锁的释放,一般写的程序的最后是一种编程习惯.

4 await()和sleep区别, await()将会让线程处于休眠状态释放掉锁. 而sleep将"持锁而睡".

 

使用conditionObject.await(long time,TimeUnit unit);

api : 此方法会等待相关的conditionObject.signal()或者conditionObject.signalAll()方法, signal或者signalAll在给定的时间time内完成,那么就返回true, 否则返回false. 注意,此方法并不是去获取锁本身,而是"等待通知".当然的,当通知出发此方法的返回时, 当前被唤醒的对象是一定会去获取lock的.

如下代码:[保证ReentrantLock和condition是同一个对象]

public void run() {
		
		lock.lock();
		try{
			if("thread_1".equals(threadName)){
				System.out.println("thread_1 到达...");
                                                   //测试代码就不写入while()中,通常情况避免虚假唤醒是要将await至于while(condition)
                                                   //中的.
				boolean result = condition.await(4, TimeUnit.SECONDS);
				if(result){
					System.out.println("true");
				}else{
					System.out.println("false");
				}
			}else{
				System.out.println("thread_2 到达...");
				//Thread.sleep(500);
				condition.signal();
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			System.out.println(threadName + "释放锁");
			lock.unlock();
		}
	}

  当应用程序在运行期间等待一个执行时间不太确定的操作时候,用此方法是很合适的. 可以用一个变量来改变下次等待的时间,如下伪代码:

    .....

    while(condition){

          try{

                boolean waitTime =conditionObject.await(wantedTime,...);  

                if(waitTime == false) {

                    //超时

                   changeWantedTime(...);

                    }

          }          

   }

  

 使用乐观的tryLock(): 当不成功时候,会迅速返回false而不是进入等待区等待.  

 

if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}



 

<to be continue...>

 

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter