Java并发编程实例--15.在同步代码块中使用条件
并发编程中有个经典问题:
生产消费者问题。
我们有一个数据缓冲区,一个或多个生产者往其中存入对象,另外一个或多个消费者从中取走。
因此,该数据缓冲区是一个共享数据结构,我们需要对其添加读取同步机制,但是我们还需要一些限制。
如果缓冲区满了,生产者不能继续向其中写入;反过来如果缓冲区空了,消费者也不能继续读取。
对于这种情况,Java提供了wait(),notify()和notifyAll()方法。
一个线程可以在同步代码块中调用wait()方法。如果它在同步块之外调用wait()方法,JVM将抛出IllegalMonitorStateException。
当线程调用wait()方法,JVM将该线程睡眠并且释放控制同步代码块的对象,并允许其他线程去执行。
如果需要再次唤醒该线程,只需要调用notify()或notifyAll()方法。
我们有一个数据缓冲区,一个或多个生产者往其中存入对象,另外一个或多个消费者从中取走。
因此,该数据缓冲区是一个共享数据结构,我们需要对其添加读取同步机制,但是我们还需要一些限制。
如果缓冲区满了,生产者不能继续向其中写入;反过来如果缓冲区空了,消费者也不能继续读取。
对于这种情况,Java提供了wait(),notify()和notifyAll()方法。
一个线程可以在同步代码块中调用wait()方法。如果它在同步块之外调用wait()方法,JVM将抛出IllegalMonitorStateException。
当线程调用wait()方法,JVM将该线程睡眠并且释放控制同步代码块的对象,并允许其他线程去执行。
如果需要再次唤醒该线程,只需要调用notify()或notifyAll()方法。
本例中,你将学习如何使用synchronized关键字和wait(), notify(), and notifyAll()方法去实现生产-消费者问题。
缓冲区类:
EventStorage.java
package com.dylan.thread.ch2.c03.task;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/**
* This class implements an Event storage. Producers will storage
* events in it and Consumers will process them. An event will
* be a java.util.Date object
*
*/
public class EventStorage {
/**
* Maximum size of the storage
*/
private int maxSize;
/**
* Storage of events
*/
private List<Date> storage;
/**
* Constructor of the class. Initializes the attributes.
*/
public EventStorage(){
maxSize=10;
storage=new LinkedList<>();
}
/**
* This method creates and storage an event.
*/
public synchronized void set(){
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.printf("Set: %d",storage.size());
notify();
}
/**
* This method delete the first event of the storage.
*/
public synchronized void get(){
while (storage.size()==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf("Get: %d: %s",storage.size(),((LinkedList<?>)storage).poll());
notify();
}
}
生产者:
Producer.java
package com.dylan.thread.ch2.c03.task;
/**
* This class implements a producer of events.
*
*/
public class Producer implements Runnable {
/**
* Store to work with
*/
private EventStorage storage;
/**
* Constructor of the class. Initialize the storage.
* @param storage The store to work with
*/
public Producer(EventStorage storage){
this.storage=storage;
}
/**
* Core method of the producer. Generates 100 events.
*/
@Override
public void run() {
for (int i=0; i<100; i++){
storage.set();
}
}
}
消费者:
Consumer.java
package com.dylan.thread.ch2.c03.task;
/**
* This class implements a consumer of events.
*
*/
public class Consumer implements Runnable {
/**
* Store to work with
*/
private EventStorage storage;
/**
* Constructor of the class. Initialize the storage
* @param storage The store to work with
*/
public Consumer(EventStorage storage){
this.storage=storage;
}
/**
* Core method for the consumer. Consume 100 events
*/
@Override
public void run() {
for (int i=0; i<100; i++){
storage.get();
}
}
}
主类:
Main.java
package com.dylan.thread.ch2.c03.core;
import com.dylan.thread.ch2.c03.task.Consumer;
import com.dylan.thread.ch2.c03.task.EventStorage;
import com.dylan.thread.ch2.c03.task.Producer;
/**
* Main class of the example
*/
public class Main {
/**
* Main method of the example
*/
public static void main(String[] args) {
// Creates an event storage
EventStorage storage=new EventStorage();
// Creates a Producer and a Thread to run it
Producer producer=new Producer(storage);
Thread thread1=new Thread(producer);
// Creates a Consumer and a Thread to run it
Consumer consumer=new Consumer(storage);
Thread thread2=new Thread(consumer);
// Starts the thread
thread2.start();
thread1.start();
}
}
运行结果:
Set: 1
Set: 2
Set: 3
Set: 4
Set: 5
Set: 6
Set: 7
Set: 8
Set: 9
Set: 10
Get: 10: Fri May 11 22:31:02 GMT+08:00 2018
Get: 9: Fri May 11 22:31:02 GMT+08:00 2018
Get: 8: Fri May 11 22:31:02 GMT+08:00 2018
Get: 7: Fri May 11 22:31:02 GMT+08:00 2018
Get: 6: Fri May 11 22:31:02 GMT+08:00 2018
Get: 5: Fri May 11 22:31:02 GMT+08:00 2018
Get: 4: Fri May 11 22:31:02 GMT+08:00 2018
Get: 3: Fri May 11 22:31:02 GMT+08:00 2018
Get: 2: Fri May 11 22:31:02 GMT+08:00 2018
Get: 1: Fri May 11 22:31:02 GMT+08:00 2018
Set: 1
Set: 2
...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构