方法1:最简单--利用LinkedBlockingQueue
队列具有先进先出的特点,成为经常应用于生产-消费者模式的数据结构。
1.将一个对象放到队列尾部,如果队列已满,就等待直到有空闲节点。 ——put()方法
2.从队列头部取一个对象,如果没有对象,就等待直到有对象可取。 ——take()方法
3.在存取队列的过程中,锁定队列对象,不允许其它线程访问队列。——使得它是线程安全的
下面的代码适用于多个生产者、多个消费者。
1 //Producer.java 2 import java.util.concurrent.BlockingQueue; 3 4 /* 5 * Usage example, based on a typical producer-consumer scenario. 6 * Note that a <tt>BlockingQueue</tt> can safely be used with multiple 7 * producers and multiple consumers. 8 * <pre> 9 */ 10 class Producer implements Runnable { 11 private BlockingQueue<Object> queue; 12 13 Producer(BlockingQueue<Object> q) { 14 queue = q; 15 } 16 17 public void run() { 18 try { 19 while (true) { 20 queue.put(produce()); 21 Thread.sleep(1); 22 System.out.println("+1 Produce an Object:" + "生产者size:" 23 + queue.size()); 24 } 25 } catch (InterruptedException ex) { 26 System.out.println("生产者结束!"); 27 } 28 } 29 30 Object produce() { 31 return new Object(); 32 } 33 }
1 //Consumer.java 2 import java.util.concurrent.BlockingQueue; 3 4 class Consumer implements Runnable { 5 private BlockingQueue<Object> queue; 6 7 Consumer(BlockingQueue<Object> q) { 8 queue = q; 9 } 10 11 public void run() { 12 try { 13 while (true) { 14 consume(queue.take()); 15 Thread.sleep(10); 16 System.out.println("-1 Consumer an Object:" + "size:"+ queue.size()); 17 } 18 } catch (InterruptedException ex) { 19 System.out.println("消费者结束!"); 20 } 21 } 22 23 void consume(Object x) { 24 } 25 }
1 import java.util.concurrent.BlockingQueue; 2 import java.util.concurrent.LinkedBlockingQueue; 3 4 class Main { 5 public static void main(String[] args) { 6 BlockingQueue<Object> q = new LinkedBlockingQueue<Object>();// SomeQueueImplementation(); 7 Producer p = new Producer(q); 8 Consumer c1 = new Consumer(q); 9 Consumer c2 = new Consumer(q); 10 Thread pth = new Thread(p); 11 pth.start(); 12 new Thread(c1).start(); 13 new Thread(c2).start(); 14 try { 15 Thread.sleep(50); 16 pth.interrupt(); 17 } catch (InterruptedException e) { 18 } 19 } 20 }
方法2:不采用BlockingQueue,利用lock、Condition来实现
思路:
利用可重用的LinkedList来存放资源,生产者addLast(),消费者removeFirst()。
使用ReentrantLock()来实现消费者和生产者的同步;//可重用的互斥锁
思考:为什么使用了lock后,还使用了它的2个newCondition,这样做有什么好处?
1 import java.util.*; 2 import java.util.concurrent.locks.Condition; 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class ProducerConsumer { 7 private static final LinkedList<Integer> buffer = new LinkedList<Integer>(); 8 private static final int BUFFERSIZE = 10; 9 private static Lock lock = new ReentrantLock();//可重用的互斥锁 10 private static Condition NotFull = lock.newCondition(); 11 private static Condition NotEmpty = lock.newCondition(); 12 13 static class Producer extends Thread { 14 public void run() { 15 while (true) { 16 // lock 17 lock.lock(); 18 if (buffer.size() == BUFFERSIZE) { 19 System.out.println("BUffer is fulls"); 20 try { 21 NotFull.await(); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } else { 26 buffer.addLast(1); 27 NotEmpty.signal(); 28 } 29 lock.unlock(); 30 // unlock 31 } 32 } 33 } 34 35 static class Consumer extends Thread { 36 public void run() { 37 while (true) { 38 // lock 39 lock.lock(); 40 if (buffer.size() == 0) { 41 System.out.println("BUffer is empty"); 42 try { 43 NotEmpty.await(); 44 } catch (InterruptedException e) { 45 e.printStackTrace(); 46 } 47 } else { 48 buffer.removeFirst(); 49 NotFull.signal(); 50 } 51 // unlock 52 lock.unlock(); 53 } 54 } 55 } 56 57 public static void main(String[] args){ 58 new Consumer().start(); 59 new Producer().start(); 60 } 61 }
关于Java线程的lock、condition、synchronized的小小总结:
1.synchronized简单易用,但是功能受局限,无法满足复杂的同步机制,比如“读者写者问题”:多个读者线程是不互斥的。
2.lock以更优雅的方式来解决线程同步,比如读写锁ReadWriteLock。
3.Condition解决线程间通信,为不同的线程建立不同的条件。
推荐博文:Java线程-锁机制
Condition可以替代传统的线程间通信,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。
——为什么方法名不直接叫wait()/notify()/nofityAll()?因为Object的这几个方法是final的,不可重写!
Condition实现了BlockingQueue的功能。
看看BlockingQueue的继承和实现。
一般的锁Lock的实现:注意ReadLock、WriteLock是内部的静态类,只有ReentrantReadWriteLock类可以调用。
读写的锁ReadWriteLock
思考:OS的信号量是什么,线程通信的方式有哪些?共享变量和消息传递。
信号量与互斥锁有什么联系?
By BYRHuangQiang 2014-03-18 09:05:30