线程同步经典案例-生产者与消费者模型-Java
消费者生产者模型在多线程中是一个经典问题
我们可以把并发的操作放在数据缓冲区内 借助 java自带的BlockingQueue
我们可以很容易的实现。
1 借助BlockingQueue
package com.lq.learn.learn.demo;
import com.lq.learn.learn.leran.Task;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class App4 {
//缓冲区
private final BlockingQueue<Task> blockingQueue;
//产品序号
private final AtomicInteger in = new AtomicInteger(0);
//初始化
public App4(int cap) {
blockingQueue = new LinkedBlockingQueue<>(cap);
}
public static void main(String[] args) {
App4 app4 = new App4(5);
//开5个生产线程
for (int i = 0; i < 5; i++)
(app4.new Producer()).start();
//开20个消费线程
for (int i = 0; i < 20; i++)
(app4.new Consumer()).start();
}
private class Producer extends Thread {
@Override
public void run() {
while (true) {
try {
Task task = new Task(in.getAndIncrement());
System.out.println(" produce ticket:" + task.number);
blockingQueue.put(task);
//模拟服务在一定时间内的波动及不稳定
Thread.sleep(500 + (long) (Math.random() * 500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class Consumer extends Thread {
@Override
public void run() {
while (true) {
try {
Task task = blockingQueue.take();
assert task != null;
System.out.println(" consume ticket: " + task.number);
Thread.sleep(500 + (long) (Math.random() * 500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
2 我们也可以自己来实现 借助 notify 和wait方法
package com.lq.learn.learn.demo;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
/**
* 生产者 消费者模型
*/
public class App2 {
//最大容量
private static final int MAX_SIZE = 10;
//数据存储区 或者 缓冲区
private static List<Object> storage = new LinkedList<>();
public static void main(String[] args) {
Thread producer = new Thread(new Producer());
Thread consumer = new Thread(new Consumer());
Thread producer2 = new Thread(new Producer());
Thread consumer2 = new Thread(new Consumer());
producer.start();
consumer.start();
producer2.start();
consumer2.start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
try {
// 每隔1秒生产一个商品
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (storage) {
if (storage.size() >= MAX_SIZE) {
try {
System.out.println(" stoargae is full waiting ");
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String data = UUID.randomUUID().toString().substring(1, 5);
if (storage.size() < MAX_SIZE)
storage.add(data);
System.out.println(" produced " + data);
System.out.println(" produced current size is " + storage.size());
storage.notify();
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (storage) {
if (storage.size() <= 0) {
try {
System.out.println(" stoage is empty waiting ");
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object data = null;
if (storage.size() > 0) {
data = storage.remove(0);
}
System.out.println(" consumeing" + data);
System.out.println(" consuming current size is " + storage.size());
storage.notify();
}
}
}
}
}
我们还可以借助 Lock 和condition 来实现 和2中的很相似,这里就不演示了 记得一定要释放锁unlock 而且最好在finally块中。