概念:
condition是基于Lock上的,通过Lock lock = new ReentrantLock();Condition con = lock.newCondition();得到实例。功能类似于:Object.wait(),Object.notify();一个锁内可以有多个Condition,即多路等待通知。
下面我们来看一个栗子:有两个线程,主线程和子线程,主线程连续输出100次,子线程连续输出50次。
实现:
public class ThreadMainAndSubOutputDemo {
// 主线程输出100次,子线程输出50次,所以有两个Runnable对象。共用一个输出对象
public static void main(String[] args) {
Output output = new Output();
new Thread(new Main(output)).start();
new Thread(new Sub(output)).start();
}
static class Main implements Runnable {
public Output output;
public Main(Output output) {
this.output = output;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
output.outMain();
}
}
}
static class Sub implements Runnable {
public Output output;
public Sub(Output output) {
this.output = output;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
output.outSub();
}
}
}
}
class Output {
Lock lock = new ReentrantLock();
public void outMain() {
lock.lock();
try {
for (int i = 1; i <= 100; i++) {
System.out.println("the main output:" + i);
}
} finally {
lock.unlock();
}
}
public void outSub() {
lock.lock();
try {
for (int i = 1; i <= 50; i++) {
System.out.println("the sub output:" + i);
}
} finally {
lock.unlock();
}
}
}
上面代码通过线程的锁机制实现线程的互斥。现在我想实现,子线程输出完然后主线程又跟着输出,按照这个规律互相交替输出完。我们用线程通信来实现这个需求,当然还可以用线程的this.wait(),this,notify();来实现。改变上面的代码:
public class ThreadMainAndSubOutputDemo {
// 主线程输出100次,子线程输出50次,所以有两个Runnable对象。共用一个输出对象
public static void main(String[] args) {
Output output = new Output();
new Thread(new Main(output)).start();
new Thread(new Sub(output)).start();
}
static class Main implements Runnable {
public Output output;
public Main(Output output) {
this.output = output;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
output.outMain();
}
}
}
static class Sub implements Runnable {
public Output output;
public Sub(Output output) {
this.output = output;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
output.outSub();
}
}
}
}
class Output {
Lock lock = new ReentrantLock();
Condition con = lock.newCondition();
boolean flag = false;
public void outMain() {
lock.lock();
try {
while(flag){//防止线程虚假唤醒
try {
con.await();//如果为true这个等待,然后唤醒sub线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 100; i++) {
System.out.println("the main output:" + i);
}
flag = true;
con.signal();
} finally {
lock.unlock();
}
}
public void outSub() {
lock.lock();
try {
while(!flag){//防止线程虚假唤醒
try {
con.await();//如果为false这个等待,然后唤醒main线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 50; i++) {
System.out.println("the sub output:" + i);
}
flag = false;
con.signal();
} finally {
lock.unlock();
}
}
}
下面我们来看看多个condition的使用,下面是一个典型的队列例子:
public class Queue {
public static void main(String[] args) {
BoundBuffer boundBuffer = new BoundBuffer();
/*ExecutorService executor = Executors.newSingleThreadExecutor();*/
for(int i=0;i<=10;i++){
new Thread(new PutsThread(boundBuffer,i)).start();
new Thread(new TakeThread(boundBuffer)).start();
}
}
static class PutsThread implements Runnable{
public BoundBuffer boundBuffer;
public int i;
public PutsThread(BoundBuffer boundBuffer,int i){
this.boundBuffer = boundBuffer;
this.i = i;
}
@Override
public void run() {
boundBuffer.put(i+"");
}
}
static class TakeThread implements Runnable{
public BoundBuffer boundBuffer;
public TakeThread(BoundBuffer boundBuffer){
this.boundBuffer = boundBuffer;
}
@Override
public void run() {
Object takeobj = boundBuffer.take();
System.out.println("take the obj:"+takeobj);
}
}
}
class BoundBuffer{
final int max = 1;
/*
* 为什么要使用两个Condition?
* 如果当只有一个Cindition的时候,当两个await()后,它只能唤醒其中一个线程,有可能只唤醒put的线程(这时候我们需要唤醒make线程)
* ,即造成 唤醒线程不明确
*/
final Lock lock = new ReentrantLock();
final Condition putcon = lock.newCondition();
final Condition makecon = lock.newCondition();
final String[] item = new String[2];
int takeptr,count,putstr;
public void put(String obj){
lock.lock();
try{
while(count == item.length){
//不要放了,已经满了,等待取走后再放入
try {
System.out.println("队列满了,等待。。。。"+obj);
putcon.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//放入
item[putstr] = obj;
System.out.println("put the obj:"+obj);
if(++putstr == item.length) putstr=0;
++count;
makecon.signal();
}finally{
lock.unlock();
}
}
public Object take(){
lock.lock();
Object takeobj = new Object();
try{
while(count == 0)
{
//没有了,等待放入在取走
try {
System.out.println("队列为空,等待。。。。");
makecon.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取了之后,取得位置要+1
takeobj = item[takeptr];
if(++takeptr == item.length) takeptr = 0;
--count;
putcon.signal();
}finally{
lock.unlock();
}
return takeobj;
}
}