jdk1.5——Lock/Condition使用

不管是一个condition  两个condition  三个condition 都需要一个标志未来判定

案例1的 flag

案例2的 count ==100   count ==0

案例3的  number =1


1 Lock和Condition简介:


Lock 替代 synchronized
比传统线程模型synchronized更加面向对象,

能够适应 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,这种灵活的锁机制;

Condition 功能类似于object.wait() 和 notify()

Condition的特点:

以前的方式只能有一个等待队列,在实际应用时可能需要多个,比如读和写。

为了这个灵活性,创建多个condition,
 互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),

 等待队列负责保存被阻塞的线程(condition完成)。

 2 lock+condition案例一,生产者消费者代码(单队列 只需要一个condition):

package thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @author zm
 * 执行结果:
第 0 次执行B
第 1 次执行A
第 1 次执行B
第 2 次执行A
第 2 次执行B
第 3 次执行A
第 3 次执行B
第 4 次执行A
第 4 次执行B
第 5 次执行A
第 5 次执行B
第 6 次执行A
第 6 次执行B
第 7 次执行A
第 7 次执行B
第 8 次执行A
第 8 次执行B
第 9 次执行A
第 9 次执行B
 *
 * 
 * 为什么需要使用condition呢?简单一句话,lock更灵活。以前的方式只能有一个等待队列,在实际应用时可能需要多个,比如读和写。为了这个灵活性,lock将同步互斥控制和等待队列分离开来,
 *  互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),等待队列负责保存被阻塞的线程(condition完成)。
 *  
 *  案例1:我生产一个面包,就通知顾客来拿
 *  condition能够实现实际业务中 多等待队列交互模式, 传统 wait() notify()只能实现一个等待队列;
 *  下面案例是使用 conditon实现 一个等待队列模式 取代 传统 wait() notify()的写法( 生产者-消费者, 我生产一个面包,就通知顾客来拿, 只有一个队列)
 *  
 *  
 *  案例2: 两队人,一队不停像100个篮子生产面包,一队不停从篮子拿走面包(阻塞队列)
 *  
 *  如果是我不停的生产面包放在篮子里,我不管消费者拿面包, notfull队列(篮子还没存放满面包队列 有自己独自的wait nodify)
 *  而消费者不停的去从篮子里拿面包,而不管生产者生产了多少,  notempty队列(篮子面包还没空队列 有自己独自的wait nodify)
 *  那么这就是两个队列,
 *  notfull队列, 只管像篮子里放面包,当100个篮子满的时,放面包动作处于等待
 *  notempty队列,只管从篮子里拿面包,当100个篮子空的时,存面包动作处于等待
 *  此时需要使用同一个lock的两个condition来实现第二个案例
 * 
 */
public class CommunicateWithConditionThread {

	// A 执行一次  B 执行一次  一共执行20次
	public static void main(String[] args) {
		
		final Out out = new Out(); // out对象就是同一个门栓
		
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				for(int i=0; i<10; i++){
					out.printA(i);
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				for(int i=0; i<10; i++){
					out.printB(i);
				}
			}
		}).start();
		
		
		
		
	}

}

class Out { //
	
	public boolean flag = true;
	Lock lock = new ReentrantLock();
	Condition conditon = lock.newCondition();  // 使用一个conditon, 模拟一组等待队列
	
	public  void printA(int i){
		lock.lock();
		try{
			while(!flag){// 当flag = false时,线程执行此业务方法时等待
				try {
					conditon.await();// 门栓等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				} 
			}
			System.out.println("第 " + i + " 次执行A,生产了面包"); // 否则直接执行业务方法
			flag = false; // 更改标志位
			conditon.signal(); // 使用方法  不要使用错了
		}finally{
			lock.unlock();
		}

	}
	
	public  void printB(int j){
		lock.lock();
		try{
			while(flag) {// 当flag = true时, 线程执行此业务方法时等待
				try {
					conditon.await();// 门栓等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				} 
			}
			System.out.println("第 " + j + " 次执行B,消费了面包");
			flag = true; // 更改标志位
			conditon.signal();  //
		}finally{
			lock.unlock();
		}
	
	}
	
}






 3 lock+condition案例二,多队列等待代码(阻塞队列 需要两个condition):

 *  案例2: 两队人,一对不停像100个篮子生产面包,一对不停从篮子拿走面包(阻塞队列)
 *  
 *  如果是我不停的生产面包放在篮子里,我不管消费者拿面包, notfull队列(篮子还没存放满面包队列 有自己独自的wait nodify)
 *  而消费者不停的去从篮子里拿面包,而不管生产者生产了多少,  notempty队列(篮子面包还没空队列 有自己独自的wait nodify)
 *  那么这就是两个队列,
 *  notfull队列, 只管像篮子里放面包,当100个篮子满的时,放面包动作处于等待
 *  notempty队列,只管从篮子里拿面包,当100个篮子空的时,存面包动作处于等待
 *  此时需要使用同一个lock的两个condition来实现第二个案例


 *  注意: count表示当前面包真实个数(生产一个 同时下个线程拿走一个 那么count = 0)
 *  items: 存放面包篮子
 *  putptr, 生产面包后 存放在篮子的角标,
 *  takeptr,取走面包时,面包所在篮子的角标



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)  // 当生产队列并发大到突然生产了100个面包时,生产队列等待
	         notFull.await();
			 // 否则执行生产面包操作, 不断向数组下一个单元格内放新面包
	       items[putptr] = x; 
	       if (++putptr == items.length) putptr = 0;// 当存放的面包到达数组最后位置时,篮子存放面包位置又从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(); // 取面包完成 解锁 让下个取面包动作执行 
	     }
	   } 
	 }

 3 lock+condition案例三,(三队列):

 扩展:  产生三个线程 A -->B -->  C ---> A   这里需要三个condition

package thread;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 三个队列下:
 * A循环打印5次, B循环打印5次 , C循环打印5次, A执行完后通知B,B 执行完后通知C, C执行完后通知A, 这种形式循环5次
 * @author zm
 *
 */
public class ThreeConditionCommunication {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		final Business business = new Business();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
					
						for(int i=1;i<=5;i++){
							business.sub1(i);
						}
						
					}
				}
		).start();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
						
						for(int i=1;i<=5;i++){
							business.sub2(i);
						}
						
					}
				}
				).start();
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
						
						for(int i=1;i<=5;i++){
							business.sub3(i);
						}
						
					}
				}
				).start();
		
		
		
	}

	static class Business {
		  Lock lock = new ReentrantLock();
		  Condition condition1 = lock.newCondition();
		  Condition condition2 = lock.newCondition();
		  Condition condition3 = lock.newCondition();
		  
		  private int num = 1;	
		  public  void sub1(int i){
			  lock.lock();
			  try{
				  while(num != 1){
					  try {
						  condition1.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				  }
					for(int j=1;j<=5;j++){
						System.out.println("sub1 thread sequence of " + j + ",loop of " + i);
					}
				  num = 2;	
				  condition2.signal();
			  }finally{
				  lock.unlock();
			  }
		  }
		  
		  public  void sub2(int i){
			  lock.lock();
			  try{
				 while(num != 2){
				  		try {
							condition2.await();
						} catch (Exception e) {
							e.printStackTrace();
						}
				  	}
					for(int j=1;j<=5;j++){
						System.out.println("sub2 thread sequence of " + j + ",loop of " + i);
					}
					 num = 3;	
					condition3.signal();
		  }finally{
			  lock.unlock();
		  }
	  }
		  
		  public  void sub3(int i){
			  lock.lock();
			  try{
				  while(num != 3){
					  try {
						  condition3.await();
					  } catch (Exception e) {
						  e.printStackTrace();
					  }
				  }
				  for(int j=1;j<=5;j++){
					  System.out.println("sub3 thread sequence of " + j + ",loop of " + i);
				  }
				  num = 1;
				  condition1.signal();
			  }finally{
				  lock.unlock();
			  }
		  }
	
	}
}

 脑图:

 



 

猜你喜欢

转载自chengjianxiaoxue.iteye.com/blog/2145261