java多线程(四)--线程锁通信(Condition)

概念:

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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值