不管是一个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(); } } } }
脑图: