一个线程负责生产,一个线程负责消费,生产满了就不能生产,必须消费,消费完了就必须让生产者生产。
因为是多线程问题,仓库是多线程共享,要注意线程同步,采用wait方法和notify方法
代码如下:
/*
wait方法和notify方法都是普通Java对象的方法
wait方法作用:让正在对象上的线程进入等待状态,并且释放掉线程占用的锁
notify方法的作用:让正在等待此对象的进程唤醒,但不会释放掉占用的锁
模拟环境:
仓库采用list集合模拟,为了方便假设只存储一个元素。
即list集合中有一个元素代表仓库满了。
没有元素即为空。
生产一个才能消费一个。
*/
import java.util.ArrayList;
import java.util.List;
public class ThreadTest {
public static void main(String[] args) {
//创建共享仓库
List list = new ArrayList();
Thread thread1 = new Thread(new Producer(list));
Thread thread2 = new Thread(new Consumer(list));
thread1.setName("生产者");
thread2.setName("消费者");
//启动线程
thread1.start();
thread2.start();
}
}
//生产线程
class Producer implements Runnable {
private List list;
public Producer(List list){
this.list = list;
}
@Override
public void run() {
//死循环模拟生产线不停
while(true){
//生产时为了保证线程安全,需要给共享仓库上锁
synchronized (list){
//判断仓库是否满,满了就不能继续生产,线程进入等待状态
if(list.size() > 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序到此处说明可以进行生产操作
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName() + "--->" + obj);
//生产结束需要唤醒消费进程
list.notify();
}
}
}
}
//消费线程
class Consumer implements Runnable {
private List list;
public Consumer(List list){
this.list = list;
}
@Override
public void run() {
//死循环模拟一直消费
while(true){
//消费时也需要对共享仓库上锁,保证线程安全
synchronized (list){
//判断仓库是否为空,空则无法继续消费,线程进入等待状态
if(list.size() == 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object obj = list.remove(0);
System.out.println(Thread.currentThread().getName() + "--->" + obj);
//消费结束需要唤醒生产进程
list.notify();
}
}
}
}
可以通过改变run方法内部判断条件扩容
执行结果如下:
重点:
wait方法让线程进入等待状态并会释放锁
notify方法只能唤醒线程不会释放锁
后续生产者消费者抢到的锁是synchronized代码块执行结束释放的,所以生产者消费者都有可能再次抢到,但是代码块判断条件会使不符合条件的一个线程进入睡眠状态,等待另一个线程完成操作唤醒它才可以继续抢夺仓库的使用权