生产者消费者是经典的线程之间同步通信问题,生产者线程只有在产品仓库中没有产品的时候才生产产品,当它生成完一个产品以后唤醒消费者线程,消费者线程只有在产品仓库中有产品的时候才能取走产品,然后唤醒生产者线程。
Java可以有好几种方法解决这个问题。首先基础的当然是用Object的wait()、notify()和notifyAll()。
产品仓库类:
class="java" name="code">//产品仓库 public class ProductStore { private boolean flag = false; public boolean hasProduct(){//是否有产品 return flag; } /** * 生产产品 * @throws Exception */ public synchronized void makeProduct() throws Exception{ while(hasProduct()){//如果生产线程唤醒的还是生产线程,这个被唤醒的生产线程将继续wait this.wait(); } Thread.sleep(300); flag = true; System.out.println(Thread.currentThread().getName()+":生产了一个产品"); this.notifyAll();//唤醒所有线程 } /** * 取走产品 * @throws Exception */ public synchronized void getProduct() throws Exception{ while(!hasProduct()){ this.wait(); } Thread.sleep(100); flag = false; System.out.println(Thread.currentThread().getName()+":取走一个产品"); this.notifyAll(); } }
?生产者类:
public class Producer implements Runnable{ ProductStore store; public Producer(ProductStore store){ this.store = store; } @Override public void run() { try { store.makeProduct(); } catch (Exception e) { e.printStackTrace(); } } }
?消费者类:
public class Consumer implements Runnable{ ProductStore store; public Consumer(ProductStore store){ this.store = store; } @Override public void run() { try { store.getProduct(); } catch (Exception e) { e.printStackTrace(); } } }
?主测试类:
public class Test3 { public static void main(String[] args) { ProductStore store = new ProductStore(); for (int i = 1; i <= 5; i++) { new Thread(new Consumer(store), "消费者"+i).start(); } for (int i = 1; i <= 5; i++) { new Thread(new Producer(store), "生产者"+i).start(); } } }
运行结果:
生产者1:生产了一个产品 消费者4:取走一个产品 生产者4:生产了一个产品 消费者5:取走一个产品 生产者2:生产了一个产品 消费者1:取走一个产品 生产者5:生产了一个产品 消费者2:取走一个产品 生产者3:生产了一个产品 消费者3:取走一个产品
?第二种方法就是利用java.util.concurrent包下的Lock得到Conditon,利用Condition的await()、signal()、signalAll()实现线程的通信:
产品仓库类:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //产品仓库 public class ProductStore { private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); //得到condition public boolean hasProduct(){//是否有产品 return flag; } /** * 生产产品 * @throws Exception */ public void makeProduct() throws Exception{ lock.lock(); try { while(hasProduct()){//如果生产线程唤醒的还是生产线程,这个被唤醒的生产线程将继续wait condition.await(); } Thread.sleep(300); flag = true; System.out.println(Thread.currentThread().getName()+":生产了一个产品"); condition.signalAll();//唤醒所有线程 } finally{ lock.unlock(); } } /** * 取走产品 * @throws Exception */ public void getProduct() throws Exception{ lock.lock(); try { while(!hasProduct()){ condition.await(); } Thread.sleep(100); flag = false; System.out.println(Thread.currentThread().getName()+":取走一个产品"); condition.signalAll(); } finally { lock.unlock(); } } }
?makeProduct和getProduct方法不再使用synchronized修饰,所以使用Lock来控制同步,conditon的await()、singal()、singalAll()分别替换了Object的wait()、notify()和notifyAll()。