生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经放入产品的缓冲区中再次投放产品。
使用synchronized关键字实现线程同步
在使用wait()和notifyAll()方法时,应注意将wait()方法放入循环中,否则会产生虚假唤醒问题。
/**
* Created by 吴海飞 on 2017-1-23.
*/
public class TestProductAndConsumer {
public static void main(String[] args){
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(pro,"生产者A").start();
new Thread(consumer,"消费者B").start();
}
}
/**
* 店员,可以进货与销售货物
*/
class Clerk{
private int product = 0;
/**
* 进货的方法
*/
public synchronized void get(){
while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("产品已满!");
try {
this.wait();//等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + ++product);
this.notifyAll();//唤醒线程
}
/**
* 销售的方法
*/
public synchronized void sale(){
while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
System.out.println("缺货……");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":"+ --product);
this.notifyAll();
}
}
/**
* 生产者
*/
class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++){
clerk.sale();
}
}
}
使用同步锁实现线程同步问题
使用同步锁时应注意lock()与unlock()方法的同步使用。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用ReentrantLock实现生产者消费者问题
* Created by 吴海飞 on 2017-1-23.
*/
public class TestReentrantLock {
public static void main(String[] args){
Clerk clerk = new Clerk();
Productor pro = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(pro,"生产者A").start();
new Thread(consumer,"消费者B").start();
new Thread(pro,"生产者C").start();
new Thread(consumer,"消费者D").start();
}
}
class Clerk{
private Lock lock = new ReentrantLock();//获取同步锁
private Condition condition = lock.newCondition();
private int product = 0;
/**
* 进货的方法
*/
public void get(){
lock.lock();//打开锁
try{
while (product>=1){//为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("产品已满!");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + ++product);
condition.signalAll();
}finally {
lock.unlock();//关闭锁
}
}
/**
* 销售的方法
*/
public void sale(){
lock.lock();//加锁
try {
while (product<=0){//为避免虚假唤醒,应该总是始终使用在循环中
System.out.println("缺货……");
try {
condition.await();//等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":"+ --product);
condition.signalAll();//唤醒等待
}finally {
lock.unlock();//释放锁
}
}
}
/**
* 生产者
*/
class Productor implements Runnable{
private Clerk clerk;
public Productor(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.get();
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 10; i++){
clerk.sale();
}
}
}