多线程中比较经典的就是生产者消费者模式了,很多复杂的模式也是在这个基础上演变的。里面也又很多的小知识点。
生产者消费者代码
public class AssemblyLine<T> {
//存放生产数据的队列
private final List<T> queue;
//最大生产值
private final int queueMaxSize;
public AssemblyLine(List<T> messageQueue, int max) {
this.queue = messageQueue;
this.queueMaxSize = max;
}
//生产者
public void produceMessage(T message) {
synchronized (queue){
while (queue.size()>=queueMaxSize){
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":produce:"+message);
queue.add(message);
queue.notifyAll();
}
}
//消费者
public void consumeMessage(){
synchronized (queue){
while (queue.isEmpty()){
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":consume:"+ queue.remove(0));
queue.notifyAll();
}
}
执行代码
public class Test {
public static void main(String[] args) {
final List<String> messageQueue=new LinkedList<>();
final int MAX_PRODUCE_SIZE=20;
AssemblyLine<String> assemblyLine = new AssemblyLine<>(messageQueue, MAX_PRODUCE_SIZE);
Stream.of("produce1","produce2","produce3").forEach(s ->
new Thread(()-> {
while (true){
assemblyLine.produceMessage(UUID.randomUUID().toString());
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},s).start()
);
Stream.of("consume1","consume2").forEach(s ->
new Thread(()->{
while (true){
assemblyLine.consumeMessage();
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},s).start()
);
}
总结
- 在生产者消费者模型中判断逻辑代码中不能使用if必须使用while,因为需要被唤醒后的生产者或者消费者去重新执行判断,否则可能一次生成多次消费,生成过剩的情况发生。
- 因为Object.notify()不能指定唤醒某个等待的线程,所以只能使用notifyAll();
网友评论