Java多线程 使用wait()和notify()还有notifyAll() 自己实现带有等待队列的多生产者多消费者的生产消费模式 详细代码

该小项目有6个类,如下:
Container.class
容纳生产者生产的消息,包含3个方法,往等待消费队列里面添加add(),取出pop()消息,获取消息的数量size(),这三个方法都是同步方法
AddService.class入队列方法类
AddValueThread.class:入队列线程类
PopService.class:出队列方法类
PopValueThread.class:出队列线程类
Test.class.class:测试类

项目代码:
Container.class

public class Container {
    private static List list = new LinkedList();
    synchronized public void add() {
        if (size() < 30) {
            list.add("1");
            System.out.println("线程:"+Thread.currentThread().getName()+
                    "执行 add() 方法,size大小为:"+size());
        }
    }
    synchronized public int size() {
        return list.size();
    }
    synchronized public Object pop() {
        Object value = list.remove(0);
        System.out.println("线程:"+Thread.currentThread().getName()+"执行" +
                "popFirst()方法,size大小为:"+size());
        return value;
    }
}

AddService.class

public class AddService {
    private Container container;
    public AddService(Container container) {
        this.container = container;
    }
    public void addMethod() {
        try {
            synchronized (container) {
                while (container.size() == 30) {
                    System.out.println("容器已满");
                    container.notifyAll();
                    container.wait();
                }
            }
            Thread.sleep(500);
            container.add();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

AddValueThread.class

public class AddValueThread extends Thread {
    private AddService addService;
    public AddValueThread(AddService addService) {
        this.addService = addService;
    }
    @Override
    public void run() {
        while (true) {
            addService.addMethod();
        }
    }
}

PopService.class

public class PopService {
    private Container container;
    public PopService(Container container) {
        this.container = container;
    }
    public void popMethod() {
        try {
            synchronized (container) {
                while (container.size() == 0) {
                    System.out.println("队列空");
                    container.notifyAll();
                    container.wait();
                }
                container.pop();
            }
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

PopValueThread.class

public class PopValueThread extends Thread{
    private PopService service;
    public PopValueThread(PopService service) {
        this.service = service;
    }
    @Override
    public void run() {
        while (true) {
            service.popMethod();
        }
    }
}

Test.class.class

public class Test {
    public static void main(String[] args) throws InterruptedException {
        //创建容器
        Container container = new Container();
        //创建入队列方法类,将容器类作为锁传入
        AddService addService = new AddService(container);
        //创建出队列方法类,将容器类作为锁传入
        PopService getService = new PopService(container);
        // 创建2个生产者线程
        for (int i = 0; i < 2; i++) {
            AddValueThread addValueThread = new AddValueThread(addService);
            addValueThread.start();
        }
        Thread.sleep(8000);
        // 创建3个消费者线程
        for (int i = 0; i < 3; i++) {
            PopValueThread popValueThread = new PopValueThread(getService);
            popValueThread.start();
        }
    }
}

这个项目有三个要注意的点
1.AddService.class的notifyAll()
为什么要用notifyAll(),而不用notify(),因为notify()可能会通知同类,消费者通知消费者,
生产者通知生产者,这样它们就会一直等待
2. AddService.class的while (container.size() == 30)
while不能使用if替代,因为wait()在被唤醒之后程序会从wait()之后开始运行,要是此时容器大小条件
不满足就会溢出,需要再次判断
3.使用Container实例对象作为锁,那么 多生产者和多消费者本质上依然是排队生产,排队消费的,
所以可用使用this作为锁对象,但是使用this作为锁对象,那说明入队列服务和出队列服务锁对象不同,
那就算它们使用notify(),也无法通知彼此,具体看 我的一篇博文 ,所以必须使用一个定时方法,让它们各自唤醒各自,这也就造成了它们通信的假象,如在AddService.class添加一个方法

public class AddService {
    private Container container;
    public AddService(Container container) {
        this.container = container;
    }
    public void addMethod() {
        try {
            synchronized (container) {
                while (container.size() == 30) {
                    System.out.println("容器已满");
                    container.notifyAll();
                    container.wait();
                }
            }
            Thread.sleep(500);
            container.add();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void notifyService() {
        try {
            while (true) {
                synchronized (this) {
                    if (box.size() < 30) {
                        this.notifyAll();
                    }
                }
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

notifyService()方法先检测容器是否以及满了,再每隔一秒唤醒所有生产者线程

上一篇:MySQL修改密码,Navicat连接MySQL时出现的1251异常处理


下一篇:【问题解决】win10连接了不可路由的以太网后,会阻止使用 WWAN 访问 Internet