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