Java线程编程——生产者消费者问题分析

接上章Java线程编程(基础知识点)。进一步讲解线程编程。

wait()方法和notify()方法。

wait()方法的本质是让执行这个方法的线程进入阻塞态;
notify()方法则相反,会唤醒处在阻塞态的相关线程。
在前面讲述进程状态变迁时,讲述过进程/线程从运行态变迁到阻塞态,会进入阻塞态多个阻塞队列中的一个队列里。为了能够唤醒这些进程/线程,系统需要知道究竟唤醒哪个队列中的进程/线程。
所以说,线程在阻塞态时,必须指明阻塞队列。
具体操作是,线程在阻塞时,必须指明一个“锁”,然后进入这个锁的阻塞队列。
所以,wait()方法必须在同步块中调用,并且必须提供锁对象!且,进程/线程的唤醒操作必须是由其它的进程/线程执行的!那么唤醒者也必须知道那个锁对象。

生产者——消费者问题分析

通过前面对生产者——消费者的问题描述可以知道,该问题涉及到两个方面,生产者(Producer)和消费者(Customer)。
下面我先给出一个接口;
接口ICommonObject:

package com.mec.about_thread.test;

import java.util.ArrayList;
import java.util.List;
//这里的操作很简单,我们只是定义了Object类型的lock对象,及一个存储数据的数组;
//因为是接口,真正实现是在Producer类和Customer类中。
public interface ICommonObject {
	//锁对象
	Object lock = new Object();
	List<Integer> numPool = new ArrayList<>();
	//set() 和 get() 就不需解释了。
	default void setNum(int num) {
		numPool.add(num);
	}
	//这里,因为我们需要知道这个numPool的情况,才能对Producer类和Customer类进行下一步操作。
	//所以,我们只需的numPool这个数组进行判断。
	default boolean isNumEmpty() {
		return numPool.isEmpty();
	}
	
	default int getNum() {
		return numPool.remove(0);
	}
	
}

生产者Producer:

package com.mec.about_thread.test;

public class Producer implements Runnable {
	private Thread thread;
	private ICommonObject commonObject;
	//这里我们可以通过内部类的形式实现找个借口,方法很多样
	public Producer(String name) {
		this.commonObject = new InnerProducer();
		this.thread = new Thread(this, name);
	}
	//开始创建线程
	public void start() {
		this.thread.start();
	}
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			synchronized (ICommonObject.lock) {
				//若numPool中是空的,说明上一次生产的数据已经被消费生产者需要继续生产,否则线程进入阻塞态。
				if (!commonObject.isNumEmpty()) {
					try {
						ICommonObject.lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				commonObject.setNum(i);
				System.out.println("生产者(" + thread.getName() + ")生产了一个数据:" + i);
				//生产者生产数据后,进入阻塞态,唤醒阻塞队列中的其他线程。
				ICommonObject.lock.notify();
			}
		}
	}
	
	class InnerProducer implements ICommonObject {
		
		public InnerProducer() {
		}
		
	}
	
}

消费者Consumer:

package com.mec.about_thread.test;

public class Consumer implements Runnable {
	private Thread thread;
	private ICommonObject commonObject;

	public Consumer() {
		this.commonObject = new InnerConsumer();
		this.thread = new Thread(this);
	}
	//开始创建线程
	public void start() {
		this.thread.start();
	}
	
	@Override
	public void run() {
		for (int i = 0; i < 200; i++) {
			synchronized (ICommonObject.lock) {
				//如果numPool中没有数据,Customer进入阻塞态,否则继续消费
				if (commonObject.isNumEmpty()) {
					try {
						ICommonObject.lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				int num = commonObject.getNum();
				System.out.println("消费者消费了" + num);
				//完成消费后,唤醒阻塞队列中的线程
				ICommonObject.lock.notify();
			}
		}
	}
	
	class InnerConsumer implements ICommonObject {
		
		public InnerConsumer() {
		}
		
	}
	
}

测试类Test:

package com.mec.about_thread.test;

public class Test {

	public static void main(String[] args) {
		Producer producer1 = new Producer("A");
		Consumer consumer = new Consumer();

		consumer.start();
		producer1.start();
		
		System.out.println("主线程主函数执行完毕!");
	}

}

执行结果:
在这里插入图片描述
这里我们就很好地完成了,生产者——消费者的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值