java 分别利用synchronized和jdk1.5新特性实现多消费者-多生产者线程的等待唤醒机制

首先,在java jdk1.5之前实现异步安全是通过关键字synchronized将对象和方法或者代码块加锁来实现的,

在生产者消费者的案例中,可以利用此方法来完成生产者生产一个消费者消费一个的控制,但有一个弊端就是, notifyAll解决了本方线程一定会唤醒对方线程的问题,但本方的线程也被唤醒了,这虽然对结果没有影响,却大大降低了效率。下面先给出通过关键字synchronized的实现:

<span style="font-size:18px;">package Test;

/*
 生产者,消费者。
 多生产者,多消费者的问题。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
notifyAll解决了本方线程一定会唤醒对方线程的问题。
*/

class Resource {
	private String name;
	private int count = 1;
	private boolean flag = false;

	public synchronized void set(String name) {

		while (flag)
			// if判断标记,只有一次,会导致不该运行的线程运行了。出现数据错误的情况,有的烤鸭没有被消费
			try {
				this.wait();
			} catch (InterruptedException e) {
			}

		this.name = name + count;// 烤鸭1 烤鸭2 烤鸭3
		count++;// 2 3 4
		System.out.println(Thread.currentThread().getName() + "...生产者..."
				+ this.name);// 生产烤鸭1 生产烤鸭2 生产烤鸭3
		flag = true;
		notifyAll();
	}

	public synchronized void out() {
		while (!flag)
			// if判断标记,只有一次,会导致不该运行的线程运行了。出现数据错误的情况,有的会被消费多次
			try {
				this.wait();
			} catch (InterruptedException e) {
			}
		System.out.println(Thread.currentThread().getName() + "...消费者........"
				+ this.name);// 消费烤鸭1
		flag = false;
		notifyAll();// 唤醒所有等待的线程 notify()为随机唤醒一个线程
	}
}

class Producer implements Runnable {
	private Resource r;

	Producer(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			r.set("烤鸭");
		}
	}
}

class Consumer implements Runnable {
	private Resource r;

	Consumer(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			r.out();
		}
	}
}

class ProducerConsumerDemo {
	public static void main(String[] args) {
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);

		t0.start();
		t1.start();
		t2.start();
		t3.start();

	}
}
</span>

jdk1.5以后将同步和锁封装成了对象。 并将操作锁的隐式方式定义到了该对象中, 将隐式动作变成了显示动作。

1. Lock接口: 替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。同时更为灵活。可以一个锁       上加上多组监视器(Condition)。
    lock():获取锁。
    unlock():释放锁,通常需要定义finally代码块中。

2. Condition接口:出现替代了Object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成ondition监视器对象。可以任意锁进行组合。对象方法有 await(),signal(),signalAll(),分别对用以前的wait(),notify(),notifyAll()方法。

具体代码(包含和上面代码的对比)如下:

<span style="font-size:18px;">package Test;

import java.util.concurrent.locks.*;

class Resource {
	private String name;
	private int count = 1;
	private boolean flag = false;

	// 创建一个锁对象。
	Lock lock = new ReentrantLock();

	// 通过已有的锁获取该锁上的监视器对象。
	// Condition con = lock.newCondition();

	// 通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
	Condition producer_con = lock.newCondition();
	Condition consumer_con = lock.newCondition();

	public void set(String name) {
		lock.lock();
		try {
			while (flag)
				// try{lock.wait();}catch(InterruptedException e){}
				try {
					producer_con.await();
				} catch (InterruptedException e) {
				}// t1 t0

			this.name = name + count;// 烤鸭1 烤鸭2 烤鸭3
			count++;// 2 3 4
			System.out.println(Thread.currentThread().getName()
					+ "...生产者5.0..." + this.name);// 生产烤鸭1 生产烤鸭2 生产烤鸭3
			flag = true;
			// notifyAll();
			// con.signalAll();
			consumer_con.signal();
		} finally {
			lock.unlock();
		}

	}

	public void out()// t2 t3
	{
		lock.lock();
		try {
			while (!flag)
				// try{this.wait();}catch(InterruptedException e){} //t2 t3
				try {
					consumer_con.await();
				} catch (InterruptedException e) {
				} // t2 t3
			System.out.println(Thread.currentThread().getName()
					+ "...消费者.5.0......." + this.name);// 消费烤鸭1
			flag = false;
			// notifyAll();
			// con.signalAll();//signalAll()也会唤醒本方线程
			producer_con.signal();
		} finally {
			lock.unlock();// 这个代码块很重要,发生了异常也要保证解锁
		}

	}
}

class Producer implements Runnable {
	private Resource r;

	Producer(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			r.set("烤鸭");
		}
	}
}

class Consumer implements Runnable {
	private Resource r;

	Consumer(Resource r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			r.out();
		}
	}
}

class ProducerConsumerDemo2 {
	public static void main(String[] args) {
		Resource r = new Resource();
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		t0.start();
		t1.start();
		t2.start();
		t3.start();

	}
}
</span>

下面说一下wait 和 sleep 区别:

1,wait可以指定时间也可以不指定。
     sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。
      wait:释放执行权,释放锁。否则将不能够被唤醒。
      sleep:释放执行权,不释放锁。自己sleep完了自己会醒



你可能感兴趣的:(异步,synchronized,Condition)