方法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
来源:https://www.cnblogs.com/byrhuangqiang/p/3606349.html
