Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用.
举例说明condition的用法:
例子一:
数组来实现任务的存取操作
package com.zhangyike.conditionConmmuication;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TwoCondition {
final Lock lock = new ReentrantLock();
/*
* 为什么需要两个Condition对象去等待和唤醒?
* 如果是一个Condition对象,那么put()方法刚放完数据,执行condition.signal();方法唤醒,如果put()和take()属于同一个Condition对象,可能唤醒的还是put()方法,当放满以后,还有很多线程要放,而取的线程抢不到执行权,放的线程来一个等一个,而取的线程拿不到执行权,这样显然没有必要。
*
* 所以用两个Condition对象,让notFull只能唤醒notEmpty,让notEmpty只能唤醒notFull。
*
*/
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];// 线程任务
/*
* putptr:数组存放指针
* takeptr:数组取的指针
* count:数组中实际的元素个数
*/
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
// 条件满足表示数组已经满,不能再放任务了,需要放弃CPU的执行权,让取任务的线程去执行
notFull.await();
// 条件已经不满足了,可以放数据。就让这个数据放到数组存放指针指向的位置
items[putptr] = x;
// 存放的指针向后移动,如果为0,就放到下标为0的第一个位置
if (++putptr == items.length)
putptr = 0;
// 数组中实际的数量加加
++count;
// 保证数据中有数据了,就可以通知非空的线程去取数据了。
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
/*
* 条件满足表示任务池中没有任务,不能取数据,就让当前线程让出cpu的执行权,让存放数据的线程去执行, 该线程等待存放的线程去唤醒他
* 被唤醒之后,继续进入while循环判断条件,条件成立则继续等待,直到被唤醒,不成立,则执行取的操作
*/
while (count == 0)
notEmpty.await();
// 条件不满足while时,去取的指针去取出一个任务
Object x = items[takeptr];
// 取的指针加加,加加后的结果如果满足条件,说明队尾的任务取出来完了,从队列开始去取。
if (++takeptr == items.length)
takeptr = 0;
// 实际的任务数量减1.
--count;
// 唤醒放任务的线程,告诉他队列中有地方放任务了,你去放吧。
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
例子二:
有两个线程,主线程和子线程。
子线程循环10次
主线程循环100次
接着子线程再循环10词,主线程再循环100次
….
如此往复循环50次。
package com.zhangyike.conditionConmmuication;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ChangeTwoThread {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
@Override
public void run() {
//往复循环50次
for (int j = 1; j < 51; j++) {
business.subThread(j);
}
}
}).start();
new Thread(
new Runnable() {
@Override
public void run() {
// 往复循环50次
for (int j = 1; j < 51; j++) {
business.mainThread(j);
}
}
}).start();
}
//当前这个类的完整名称是 ChangeTwoThread.Business
static class Business{
private boolean flag = true;//true表示子线程运行,false表示主线程运行,是两个线程运行的桥梁。由这个变量去实现线程的交互
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();//实现线程之间通信
public void subThread(int j){
lock.lock();
try{
while (!flag) {
try {
//不是我的执行权,我放弃执行
// this.wait();没有Sychronize就不能用wait
condition.await();//等待状态
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 0; i < 10; i++) {
System.out.println("sub thread start :" + i + ",lop"
+ j + "-----------------------------");
}
flag = false;
//子线程运行完成后,主线程可能还处于等待状态,没有运行的资格,所以需要唤醒
// this.notify();
condition.signal();
}finally{
lock.unlock();
}
}
public void mainThread(int j){
lock.lock();
try{
/*
* 为什么用while循环,防止虚假唤醒,用if的话:如果该线程被唤醒后的条件还是flag = true,那么就直接执行了,
* 这明显不满足题意,所以要再次判断下,满足条件再去执行,不满足条件,继续等着。。
*/
while (flag) {//唤醒之后再次去检验
try {
//不是我的执行权,我放弃执行,锁是谁,谁等待。
// this.wait();
condition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 让子线程循环10次
for (int i = 0; i < 100; i++) {
System.out.println("main thread start :" + i + ",lop"
+ j);
}
flag = true;
//主线程运行完成后,子线程可能还处于等待状态,没有运行的资格,所以需要唤醒
condition.signal();
}finally{
lock.unlock();
}
}
}
}
例子三:实现三个状态的交换
/*
* 三个线程
* 第一个执行10次。
* 第二个执行20次
* 第三个执行30次
*
*这样循环执行50次,相当于每个线程中的代码都执行50次。
*/
package com.zhangyike.conditionConmmuication;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreeThread {
public static void main(String[] args) {
final ThreeThread.MyThread my = new ThreeThread.MyThread();
//在主线程中开启三个线程,让每个线程执行50次
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
my.sub1(i);
}
System.out.println();
System.out.println();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
my.sub2(i);
}
System.out.println();
System.out.println();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
my.sub3(i);
}
System.out.println();
System.out.println();
}
}).start();
}
static class MyThread{
Lock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
Condition c3 = lock.newCondition();
int condition = 1;
final static int ONE = 1;
final static int TWO = 2;
final static int THREE = 3;
public void sub1(int times){
lock.lock();
try{
while (condition != 1) {//条件判断
try {
c1.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 0; i < 1; i++) {
System.out.println(Thread.currentThread().getName() + ",times:" + times + ", c1 = " + i);
}
//切换条件
condition = 2;//让条件等于2
c2.signal();//唤醒2,让2去执行
}finally{
lock.unlock();
}
}
public void sub2(int times){
lock.lock();
try{
while (condition != 2) {
try {
c2.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 0; i < 2; i++) {
System.out.println(Thread.currentThread().getName() + ",times:" + times + ", c2 = " + i + "-------");
}
condition = 3;//让条件等于3
c3.signal();//唤醒3,让3去执行
}finally{
lock.unlock();
}
}
public void sub3(int times){
lock.lock();
try{
while (condition != 3) {
try {
c3.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + ",times:" + times + ", c2 = " + i + "+++++++++++++++++++++++");
}
condition = 1;//让条件等于3
c1.signal();//唤醒3,让3去执行
}finally{
lock.unlock();
}
}
}
}