Java中一共有四种方法支持同步,实现生产者消费者模型,不管哪一种,都是用Queue作为缓冲队列(常用前三种):
(1)Object的wait() / notify()方法
(2)Lock和Condition的await() / signal()方法
(3)BlockingQueue阻塞队列方法
(4)PipedInputStream / PipedOutputStream

- wait()/ nofity()方法是基类Object的两个方法,所有Java类都会拥有这两个方法,这样我们就可以为任何对象实现同步机制。wait(),当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。notify()/notifyAll(),当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待获取该临资的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
//启动类
public class ProductConsumer{
public static void main(String[] args) throws InterruptedException{
Queue<Integer> queue=new LinkedList<Integer>();
Product product=new Product(queue,3,"生产者-1");
//此处还可以设置更多生产者...
Consumer consumer=new Consumer(queue,3,"消费者-1");
//此处还可以设置更多消费者...
Thread t1=new Thread(product);
Thread t2=new Thread(consumer);
t1.start();
t2.start();
}
}
//生产者
public class Product implements Runnable {
private String name;
private int now=1;
private Queue queue;
private int maxSize;
public Product(Queue q,int max,String name){
this.name=name;
this.queue=q;
this.maxSize=max;
}
@Override
public void run() {
while(true){
synchronized(queue){
while(queue.size()==maxSize){
System.out.println("队列满了,"+this.name+"等待...");
try {
queue.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(this.name+"生产:"+now);
queue.offer(now++);
queue.notifyAll();
try {
//此步很重要,生产者生产完必须等待一段时间以被消费
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
//消费者
public class Consumer implements Runnable {
private String name;
private Queue queue;
private int maxSize;
public Consumer(Queue queue,int max,String name){
this.name=name;
this.queue=queue;
this.maxSize=max;
}
@Override
public void run() {
while(true){
synchronized(queue){
while(queue.isEmpty()){
try {
System.out.println("队列为空,"+this.name+"等待...");
queue.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int c=(Integer) queue.poll();
System.out.println("消费者"+this.name+"吃了:"+c);
queue.notifyAll();
try {
//此步很重要,消费者消费完必须等待一段时间以被生产
Thread.sleep(new Random().nextInt(1000));/
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

- 使用Lock和Condition的await() / signal()方法,await() 让线程"条件等待",并自动释放Lock锁,signal()/signalAll()对线程"条件唤醒",并重新获得锁
(以下模拟存取款同步操作)
//启动类
public class Test {
private static Account account=new Account(0,20);//初始余额0元,账户最大存储余额20元
public static void main(String[] args){
ExecutorService executorService=Executors.newCachedThreadPool();
executorService.execute(new Deposit(account));
executorService.execute(new Withdraw(account));
executorService.shutdown();
}
}
//账户
public class Account {
private static int balance=0;//账户余额
private static int maxBalance=0;//该账户最大存储余额maxBalance元
private static Lock lock=new ReentrantLock();
private static Condition lessMoney=lock.newCondition();//条件:余额不够
private static Condition fullMoney=lock.newCondition();//条件:账户余额超过20元
public Account(int b,int max){
this.balance=b;
this.maxBalance=max;
}
public void deposit(int amount){
lock.lock();
try{
while(balance+amount>maxBalance){
System.out.println("余额超额!现余"+balance+"元,最大存款额"+maxBalance+"元,存入后余"+(balance+amount)+"元,等待取款...");
fullMoney.await();//此锁条件等待
}
balance+=amount;
lessMoney.signalAll();//此锁条件唤醒
System.out.println("存入"+amount+"元!余"+balance+"元");
}catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void withdraw(int amount){
lock.lock();
try{
while(amount>balance){
System.out.println("余额不够:余"+balance+"元,"+"取"+amount+"元,等待存款...");
lessMoney.await();
}
balance-=amount;
fullMoney.signalAll();
System.out.println("取出"+amount+"元!余"+balance+"元");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
//存款线程(生产者)
public class Deposit implements Runnable {
private Account account;
public Deposit(Account a){
account=a;
}
@Override
public void run() {
while(true){
try {
account.deposit((int)(Math.random()*10+1));//每次存入1-10元
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//取款线程(消费者)
public class Withdraw implements Runnable {
private Account account;
public Withdraw(Account a){
this.account=a;
}
@Override
public void run() {
while(true){
try {
account.withdraw((int)(Math.random()*10+1));//每次取出1-10元
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

- 使用BlockingQueue阻塞队列
可以使用LinkedBlockingQueue,它是内部已实现了同步的队列,实现方式采用的是await()/ signal()方法。它可以在生成对象时指定容量大小,入队put()队列满了自动阻塞,出队take()队列为空自动阻塞。
//启动类
public class Test {
public static void main(String[] args){
BlockingQueue<Integer> queue=new LinkedBlockingQueue<Integer>(3);//指定队列容量3
Product product=new Product(queue,"生产者-1");
Consumer consumer=new Consumer(queue,"消费者-1");
product.start();
consumer.start();
}
}
//生产者
public class Product extends Thread {
private static BlockingQueue queue;
private static int i=0;
private String name;
public Product(BlockingQueue q,String n){
this.queue=q;
this.name=n;
}
public void run(){
try {
while(true){
queue.put(i);
System.out.println(this.name+"生产:"+i);
i++;
//此步很重要,生产者生产完必须等待一段时间以被消费
Thread.sleep(new Random().nextInt(1000));//最多1s
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//消费者
public class Consumer extends Thread{
private static BlockingQueue queue;
private String name;
public Consumer(BlockingQueue q,String n){
this.queue=q;
this.name=n;
}
public void run(){
try {
while(true){
int i=(Integer) this.queue.take();
System.out.println(this.name+"吃了:"+i); //此步很重要,消费者消费完必须等待一段时间以被生产
Thread.sleep(new Random().nextInt(2000));
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

来源:https://www.cnblogs.com/afei1759/p/11094875.html