基于白嫖黑马程序员白嫖视频:全面深入学习java并发编程,java基础进阶中级必会教程
1 场景
生产者负责生产对象,消费者负责拿走对象,中间维护一个消息队列。
2 代码
2.1 消息
//消息类,只能读
final class Message {
private int id;//消息的id
private Object object;//消息的值
Message(int id, Object object) {
this.id = id;
this.object = object;
}
public int getId() {
return id;
}
public Object getObject() {
return object;
}
}
2.2 消息队列
//消息队列
final class MessageQueue {
private int maxLength;//最大长度
private LinkedList<Message> list;//队列
//只能有参构造
MessageQueue(int maxLength) {
this.maxLength = maxLength;
list = new LinkedList<Message>();
}
//得到消息方法
public Message take() {
synchronized (list) {
while (list.isEmpty()) {//如果为空就一直等
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//不为空了,取一个并通知打大家
Message message = list.removeFirst();
list.notifyAll();
return message;
}
}
//加入消息队列
public void put(Message message) {
synchronized (list) {
while (list.size() == this.maxLength) {//如果已经满了就等待
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有空位,加到最后面
list.addLast(message);
list.notifyAll();
}
}
}
关键就在于生产和消费的方法的逻辑编写。
3.3 测试主类
public class Main {
public static void main(String[] args) {
MessageQueue messageQueue = new MessageQueue(3);
//生产者,启动10个线程创建
for (int i = 0; i < 10; i++) {
int id = i;//每次循环都产生新的id变量
new Thread(() -> {
System.out.println("生产者:" + id + " 生产消息");
messageQueue.put(new Message(id, "消息"));
}).start();
}
//消费者,一直取
new Thread(() -> {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = messageQueue.take();
System.out.println("消费者:" + " 获得消息" + message.getId());
}
}).start();
}
}
运行结果:
生产者:2 生产消息
生产者:1 生产消息
生产者:3 生产消息
生产者:6 生产消息
生产者:0 生产消息
生产者:9 生产消息
生产者:8 生产消息
生产者:5 生产消息
生产者:7 生产消息
生产者:4 生产消息
消费者: 获得消息2
消费者: 获得消息1
消费者: 获得消息3
消费者: 获得消息6
消费者: 获得消息4
消费者: 获得消息0
消费者: 获得消息7
消费者: 获得消息8
消费者: 获得消息5
消费者: 获得消息9
当运行完之后,消费者依然想消费,但是消息队列为空,所以他还在等待。
3 总结
生产者消费者模式应用非常广泛,需要掌握。