生产者消费者问题是一个经典的问题,一般情况下都会使用synchronized关键字来对生产和消费逻辑进行加锁
,最近学习了下并发编程相关的基础知识,尝试使用其它的几种方法来实现生产者和消费者模型。
使用synchronized来实现生产者消费者模式中规中矩
package com.mnmlist.concurrent.producerConsumerModel.synchronizedDemo;
import com.mnmlist.constant.Constant;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author [email protected]
* @date 2017/05/07
* @time 14:58
*/
public class SynchronizedDemo {
public static void main(String[] args) {
Queue queue = new LinkedList();
int count = 100; // 最多能生产的商品数量
int consumeNum = 2;
int produceNum = 5;
Storage storage = new Storage(queue, count, Constant.QUEUE_MAX_INDEX, 0);
Consumer c1 = new Consumer(consumeNum, storage);
Consumer c2 = new Consumer(consumeNum, storage);
Producer p1 = new Producer(produceNum, storage);
Producer p2 = new Producer(produceNum, storage);
Producer p3 = new Producer(produceNum, storage);
Producer p4 = new Producer(produceNum, storage);
new Thread(c1).start();
new Thread(c2).start();
new Thread(p1).start();
new Thread(p2).start();
new Thread(p3).start();
new Thread(p4).start();
}
}
class Goods {
private int index;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return "Goods{" +
"index=" + index +
'}';
}
}
class Storage {
private Queue queue;
private int count;
private int maxIndex;
private Integer index;
public Storage(Queue queue, int count, int maxIndex, int index) {
this.queue = queue;
this.count = count;
this.maxIndex = maxIndex;
this.index = index;
}
public void consume(int num) {
synchronized (this) {
while (queue.size() < num) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < num; i++) {
Goods goods = queue.remove();
System.out.println("consume thread=" + Thread.currentThread() + "goods=" + goods + ",list.size=" + queue.size());
}
this.notifyAll();
}
}
public void produce(int num) {
synchronized (this) {
while (queue.size() + num > count) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < num; i++) {
Goods goods = new Goods();
synchronized (index) {
goods.setIndex(++index);
}
queue.add(goods);
System.out.println("produce thread=" + Thread.currentThread() + "newGoods="
+ goods + ",list.size=" + queue.size());
}
this.notifyAll();
}
}
}
class Producer implements Runnable {
private Storage storage;
private int num;
public Producer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.produce(num);
}
}
}
class Consumer implements Runnable {
private Storage storage;
private int num;
public Consumer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.consume(num);
}
}
}
1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
ReentrantLock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
注意:使用ReentrantLock必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放!这一点区别看起来可能没什么,但是实际上,它极为重要。忘记在 finally 块中释放锁,可能会在程序中留下一个定时炸弹,当有一天炸弹爆炸时,您要花费很大力气才有找到源头在哪。而使用同步,JVM 将确保锁会获得自动释放。
package com.mnmlist.concurrent.producerConsumerModel.concurrentLock;
import com.mnmlist.constant.Constant;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author [email protected]
* @date 2017/05/07
* @time 14:58
*/
public class ReentrantLockDemo {
public static void main(String[] args) {
Queue queue = new LinkedList();
int count = 100; // 最多能生产的商品数量
int consumeNum = 7;
int produceNum = 3;
Storage storage = new Storage(queue, count, Constant.QUEUE_MAX_INDEX, 0);
Consumer c1 = new Consumer(consumeNum, storage);
Consumer c2 = new Consumer(consumeNum, storage);
Consumer c3 = new Consumer(consumeNum, storage);
Consumer c4 = new Consumer(consumeNum, storage);
Producer p2 = new Producer(produceNum, storage);
Producer p1 = new Producer(produceNum, storage);
new Thread(c1).start();
new Thread(c2).start();
new Thread(c3).start();
new Thread(c4).start();
new Thread(p1).start();
new Thread(p2).start();
}
}
class Goods {
private int index;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return "Goods{" +
"index=" + index +
'}';
}
}
class Storage {
ReentrantLock lock = new ReentrantLock();
Condition consumeCondition = lock.newCondition();
Condition produceCondition = lock.newCondition();
Queue queue;
private int count;
private int maxIndex;
private Integer index;
public Storage(Queue queue, int count, int maxIndex, int index) {
this.queue = queue;
this.count = count;
this.maxIndex = maxIndex;
this.index = index;
}
public void consume(int num) {
lock.lock();
try {
while (queue.size() < num) {
consumeCondition.await();
}
for (int i = 0; i < num; i++) {
Goods goods = queue.remove();
System.out.println("consume thread=" + Thread.currentThread() + "goods=" + goods + ",list.size=" + queue.size());
}
produceCondition.signalAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
public void produce(int num) {
lock.lock();
try {
while (queue.size() + num > count) {
produceCondition.await();
}
for (int i = 0; i < num; i++) {
Goods goods = new Goods();
synchronized (index) {
goods.setIndex(++index);
}
queue.add(goods);
System.out.println("produce thread=" + Thread.currentThread() + "newGoods="
+ goods + ",list.size=" + queue.size());
}
consumeCondition.signalAll();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable {
private Storage storage;
private int num;
public Producer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.produce(num);
}
}
}
class Consumer implements Runnable {
private Storage storage;
private int num;
public Consumer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.consume(num);
}
}
}
实现生产者消费者模式的最简单的方式,不用提供额外的同步,因为BlockingQueue在底层就是线程安全的,它使用ReentrantLock来保证线程安全
package com.mnmlist.concurrent.producerConsumerModel.BlockingQueue;
import com.mnmlist.constant.Constant;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
/**
* @author [email protected]
* @date 2017/05/07
* @time 14:58
*/
public class BlockingQueueDemo {
public static void main(String[] args) {
int count = 100; //最多能生产的商品的数量
int consumeNum = 3;
int produceNum = 7;
BlockingQueue blockingQueue = new LinkedBlockingDeque(count);
Storage storage = new Storage(blockingQueue, count, Constant.QUEUE_MAX_INDEX, 0);
Consumer c1 = new Consumer(consumeNum, storage);
Consumer c2 = new Consumer(consumeNum, storage);
Producer p2 = new Producer(produceNum, storage);
Producer p1 = new Producer(produceNum, storage);
Producer p3 = new Producer(produceNum, storage);
Producer p4 = new Producer(produceNum, storage);
new Thread(p1).start();
new Thread(p2).start();
new Thread(p3).start();
new Thread(p4).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
class Goods {
private int index;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return "Goods{" +
"index=" + index +
'}';
}
}
class Storage {
BlockingQueue blockingQueue;
private int count;
private int maxIndex;
private Integer index;
public Storage(BlockingQueue blockingQueue, int count, int maxIndex, int index) {
this.blockingQueue = blockingQueue;
this.count = count;
this.maxIndex = maxIndex;
this.index = index;
}
public void consume(int num) {
for (int i = 0; i < num; i++) {
Goods goods = null;
try {
goods = blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("consume thread=" + Thread.currentThread() + "goods=" + goods + ",list.size=" + blockingQueue.size());
}
}
public void produce(int num) {
for (int i = 0; i < num; i++) {
Goods goods = new Goods();
synchronized (index) {
goods.setIndex(++index);
}
try {
blockingQueue.put(goods);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("produce thread=" + Thread.currentThread() + "newGoods=" + goods + ",list.size=" + blockingQueue.size());
}
}
}
class Producer implements Runnable {
private Storage storage;
private int num;
public Producer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.produce(num);
}
}
}
class Consumer implements Runnable {
private Storage storage;
private int num;
public Consumer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.consume(num);
}
}
}
使用信号量来实现生产者和消费者模式并不是一个很好的注意,代码复杂,线程间同步比较麻烦
package com.mnmlist.concurrent.producerConsumerModel.semaphore;
import com.mnmlist.constant.Constant;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;
/**
* @author [email protected]
* @date 2017/05/07
* @time 14:58
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Queue queue = new LinkedList();
int count = 100;
int consumeNum = 3;
int produceNum = 7;
Storage storage = new Storage(queue, count, Constant.QUEUE_MAX_INDEX, 0);
Consumer c1 = new Consumer(consumeNum, storage);
Consumer c2 = new Consumer(consumeNum, storage);
// Consumer c3 = new Consumer(consumeNum, storage);
// Consumer c4 = new Consumer(consumeNum, storage);
Producer p2 = new Producer(produceNum, storage);
Producer p1 = new Producer(produceNum, storage);
Producer p3 = new Producer(produceNum, storage);
Producer p4 = new Producer(produceNum, storage);
new Thread(c1).start();
new Thread(c2).start();
// new Thread(c3).start();
// new Thread(c4).start();
new Thread(p1).start();
new Thread(p2).start();
new Thread(p3).start();
new Thread(p4).start();
}
}
class Goods {
private int index;
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public String toString() {
return "Goods{" +
"index=" + index +
'}';
}
}
class Storage {
Semaphore mutaxSemaphore;
Semaphore consumerSemaphore;
Semaphore producerSemaphore;
Queue queue;
private int count;
private int maxIndex;
private Integer index;
public Storage(Queue queue, int count, int maxIndex, int index) {
this.queue = queue;
this.count = count;
this.maxIndex = maxIndex;
this.index = index;
mutaxSemaphore = new Semaphore(1); // 用来控制同时生产或消费的只有一个线程
consumerSemaphore = new Semaphore(0); //在开始时能消费的商品数量为0个
producerSemaphore = new Semaphore(count); //刚开始最多能生产count个商品
}
public void consume(int num) {
try {
consumerSemaphore.acquire(num);
mutaxSemaphore.acquire();
for (int i = 0; i < num; i++) {
Goods goods = queue.poll();
if(null == goods) {
consumerSemaphore.release(num - i); //消费失败,把还没有消费的占用的信号量release掉
synchronized (index) {
++ index;
}
} else {
System.out.println("consume thread=" + Thread.currentThread() + "goods=" + goods + ",list.size=" + queue.size());
producerSemaphore.release(); // 每消费一个商品释放一个信号量
}
}
mutaxSemaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void produce(int num) {
try {
producerSemaphore.acquire(num); //每次先阻塞获取num个信号量
mutaxSemaphore.acquire();
for (int i = 0; i < num; i++) {
Goods goods = new Goods();
synchronized (index) {
goods.setIndex(++index);
}
boolean isSuccess = queue.add(goods);
if(!isSuccess) {
producerSemaphore.release(num - i); //生产失败,把还没有生产的所占用的信号量release掉
synchronized (index) {
-- index;
}
} else {
System.out.println("produce thread=" + Thread.currentThread() + "newGoods=" + goods + ",list.size=" + queue.size());
consumerSemaphore.release(); //没生产一个商品增加一个可消费的信号量
}
}
mutaxSemaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer implements Runnable {
private Storage storage;
private int num;
public Producer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.produce(num);
}
}
}
class Consumer implements Runnable {
private Storage storage;
private int num;
public Consumer(int num, Storage storage) {
this.num = num;
this.storage = storage;
}
public void run() {
while (true) {
storage.consume(num);
}
}
}