Java多线程解决生产者消费者问题是一种实际运用场景中非常常见的技术,本文将详细讲解Java多线程解决生产者消费者问题的完整攻略。
生产者消费者问题简介
生产者消费者问题是一种典型的同步问题,多个线程同时对共享资源进行读、写操作时容易出现数据不一致的情况。生产者生产数据,消费者消费数据,二者同时操作一个队列,但是若在操作队列时没有合理的同步策略,就会出现生产者生产的数据消费者消费不到或消费者轮流消费同一个数据等问题。因此,需要用到同步策略技术。
Java实现生产者消费者问题的方法
Java中提供了多种方式解决生产者消费者问题,例如使用wait()、notify()、BlockQueue等方法。
1. 使用wait()和notify()
wait()和notify()是Object类中定义的方法,用于在多线程程序中进行同步。
在使用wait()和notify()方法时,需要保证以下几点:
- 1) wait()和notify()方法只能在同步方法/块中调用;
- 2) wait()和notify()方法必须从synchronized方法调用;
- 3) wait()方法会释放占用的锁,使得线程进入等待状态。notify()方法会唤醒等待的线程。
示例代码如下:
public class ProducerConsumer {
private List<String> storage = new LinkedList<String>(); // 生产消费的队列
private final int MAX = 10; // 最大存储量
public ProducerConsumer() {
}
public void produce() {
synchronized(storage) {
while (storage.size() == MAX) { // 队列已经达到最大容量,等待消费者消费
try {
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date().toString()); // 生产一个产品
System.out.println("Added, the storage has " + storage.size() + " products now.");
storage.notifyAll(); // 唤醒所有等待线程
}
}
public void consume() {
synchronized(storage) {
while (storage.size() == 0) { // 队列已经空了,等待生产者生产
try {
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.poll(); // 消费一个产品
System.out.println("Polled, the storage has " + storage.size() + " products now.");
storage.notifyAll(); // 唤醒所有等待线程
}
}
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
new Producer(pc).start(); // 启动生产者
new Consumer(pc).start(); // 启动消费者
}
}
class Producer extends Thread {
private ProducerConsumer pc;
public Producer(ProducerConsumer pc) {
this.pc = pc;
}
public void run() {
while (true) {
pc.produce();
}
}
}
class Consumer extends Thread {
private ProducerConsumer pc;
public Consumer(ProducerConsumer pc) {
this.pc = pc;
}
public void run() {
while (true) {
pc.consume();
}
}
}
在该示例中,ProducerConsumer类是一个线程共享的队列,Producer和Consumer继承自Thread,启动生产者和消费者线程。当生产者生产的产品数量达到最大容量时,会进入等待状态,并调用storage.wait()方法,一旦有消费者消费产品时,会调用storage.notifyAll()方法唤醒所有等待的线程。
2. 使用BlockingQueue
BlockingQueue是Java提供的线程安全的队列,可以用来实现生产者消费者模式的同步操作。
BlockingQueue的主要方法包括put()、take()以及offer()、poll()、peek()等,使用它们可以比较方便地实现队列的操作。
示例代码如下:
public class ProducerConsumer {
private BlockingQueue<String> queue = new LinkedBlockingQueue<>(10); // 生产消费的队列
public ProducerConsumer() {
}
public void produce() {
try {
queue.put(new Date().toString()); // 生产一个产品
System.out.println("Added, the storage has " + queue.size() + " products now.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void consume() {
try {
queue.take(); // 消费一个产品
System.out.println("Polled, the storage has " + queue.size() + " products now.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
new Producer(pc).start(); // 启动生产者
new Consumer(pc).start(); // 启动消费者
}
}
class Producer extends Thread {
private ProducerConsumer pc;
public Producer(ProducerConsumer pc) {
this.pc = pc;
}
public void run() {
while (true) {
pc.produce();
}
}
}
class Consumer extends Thread {
private ProducerConsumer pc;
public Consumer(ProducerConsumer pc) {
this.pc = pc;
}
public void run() {
while (true) {
pc.consume();
}
}
}
在该示例中,ProducerConsumer类仍然是一个线程共享的队列,Producer和Consumer继承自Thread,启动生产者和消费者线程。生产和消费的操作分别使用put()、take()方法实现,这两个方法是线程安全的,可以保证在多线程中对队列的操作是同步的。
以上是Java多线程解决生产者消费者问题的完整攻略,希望对读者有所帮助!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java多线程解决生产者消费者问题 - Python技术站