线程通信之生产者和消费者案例

使用 Object 类的 wait() 和 notify() 方法 (不适用锁机制)

只有同步监听对象才可以调用 wait() 和 notify() 方法,否则报错
线程之间进行通信,且防止耦合度过高,使用一个中间类作为通信的共同资源

  • 需要使用 synchronized 保证一个过程的原子性
  • 使用 isEmpty 变量作为标志参数,在结束生产和结束消费之后改变该值
  • 使用 Object 类的 wait() 方法,判断资源状态,若存在则当前进程进入等待池
  • 使用 Object 类的 notify() 方法,在结束生产和结束消费之后唤醒其他线程
  • 值得注意的是:只有同步监听对象才可以调用 wait() 和 notify() 方法,否则报错

测试类

source 作为两个线程的参数传入

public class TestDemo {
	public static void main(String[] args) {
		ShareSources source = new ShareSources();
		new Producer(source).start();
		new Comsumer(source).start();
	}
}

资源类

public class ShareSources {
	private String name;
	private String sex;
	private Boolean isEmpty = true;//使用一个参数作为标志

	/**
	 * 存入数据
	 * @param name
	 * @param sex
	 */
	synchronized public void push(String name, String sex) {//同步方法,保证了该方法的原子性
		try {
			//此处使用While比If更加合理,
			while (!isEmpty) {// 生产者是当前线程,如果资源任存在,则当前线程释放锁,进入等待池中,释放后,消费者进程获得锁
				this.wait();//this 指的是 source 对象 进入等待池中的线程只能被其他线程唤醒,这里只能在消费者线程中唤醒
			}
			//---------------------开始生产-------------------------
			this.name = name;
			Thread.sleep(10);
			this.sex = sex;
			//---------------------结束生产-------------------------
			isEmpty = false;
			this.notifyAll();//同时将其他线程唤醒
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 获取资源
	 */
	synchronized public void get() {
		try {
			while (isEmpty) {//如果资源不存在
				this.wait();//当前线程是消费者,进入等待池
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//---------------------开始消费-------------------------
		Thread.sleep(10);		
		System.out.println(this.name + "-" + this.sex);
		//---------------------结束消费-------------------------
		isEmpty = true;
		this.notifyAll();//同时将其他线程唤醒
	}
}

生产者类

生产者可能存在多个,且需要与消费者不同线程

public class Producer extends Thread {
	private ShareSources source = null;

	public Producer(ShareSources source) {//通过构造器获取相同的资源
		this.source = source;
	}

	@Override
	public void run() {
		for (int i = 0; i < 50; i++) {
			if (i % 2 == 0) {
				source.push("春哥", "男");
			}else {
				source.push("凤姐", "女");
			}
		}
	}
}

消费者类

public class Comsumer extends Thread {
	private ShareSources source = null;

	public Comsumer(ShareSources source) {
		this.source = source;
	}

	public void run() {
		for (int i = 0; i < 50; i++) {
			source.get();
		}
	}
}

使用 Lock 和 condition 接口

资源类(只有该类发生变化)

需要注意的是,condition 的操作一定要在获取锁之后,释放锁之前执行,否则报错

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ShareSources {
	private String name;
	private String sex;
	private Boolean isEmpty = true;
	// 实例化锁
	private final Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();// 由于Condition是一个接口,lock.newCondition()方法返回一个绑定的Condition实例

	/**
	 * 存入数据
	 * 
	 * @param name
	 * @param sex
	 */
	public void push(String name, String sex) {
		lock.lock();
		try {
			if (!isEmpty) {
				condition.await();// 使用condition的await()方法相当于 Object 类的 wait 方法
			}
			this.name = name;
			Thread.sleep(10);
			this.sex = sex;
			isEmpty = false;
			condition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	/**
	 * 获取资源
	 */
	public void get() {
		lock.lock();
		try {
			if (isEmpty) {
				condition.await();// 使用condition的await()方法相当于 Object 类的 wait 方法
			}
			Thread.sleep(10);
			System.out.println(this.name + "-" + this.sex);
			isEmpty = true;
			condition.signalAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}
posted @ 2017-08-08 16:58  岑忠满  阅读(219)  评论(0编辑  收藏  举报