博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用wait-notify实现生产消费模式
阅读量:4982 次
发布时间:2019-06-12

本文共 4585 字,大约阅读时间需要 15 分钟。

公司的一道考试题:设计一个符合生产者和消费者问题的程序。对一个对象(枪膛)进行操作,其最大容量是12颗子弹。生产者线程是一个压入线程,它不断向枪膛中压入子弹;消费者线程是一个射出线程,它不断从枪膛中射出子弹。要求:(1)为了防止两个线程访问一个资源时出现忙等待,要使用的wait-notify函数,是两个线程交替执行;(2)程序输出,要模拟体现对枪膛的压入和射出操作;

1. 任务对象:子弹

public class Task implements Runnable{     private static final Logger LOG = LoggerFactory.getLogger(Task.class);        private static AtomicInteger index = new AtomicInteger(0);        private int currentIndex;        public Task(){        currentIndex = index.incrementAndGet();    }        @Override    public void run() {        LOG.info("子弹" + currentIndex + "执行飞行");     }     public String getIndex(){        return String.valueOf(currentIndex);    }}

2. 使用wait-notify实现的任务管理容器

public class TaskManager
{ private static final Logger LOG = LoggerFactory.getLogger(TaskManager.class); private static final int SIZE = 12; private AtomicInteger count = new AtomicInteger(0); /** * 使用wait-notify及普通list构建个可以阻塞等待的容器。相当于LinkedBlockingQueue */ List
taskList = new LinkedList
(); public synchronized void put(T task) throws InterruptedException{ while(isFull()){ wait(); } boolean isEmpty = isEmpty(); taskList.add(task); count.incrementAndGet(); /** * 这里加一个isEmpty判断减少唤醒的次数,因为没必要每次put都进行唤醒,只有放入之前是empty的时候才需要唤醒customer. * 如果每次都唤醒,使producer与customer交替执行。size=12也没有意义了。 * 这里put与take等待的其实是两个不同的条件,如果使用Condition来代替内置锁的wait-notify可以更好的降低在锁上面的竞争 */ if(isEmpty){ LOG.info("唤醒消费者线程"); notifyAll(); } } public synchronized T take() throws InterruptedException{ while(isEmpty()){ wait(); } boolean isFull = isFull(); T task =taskList.remove(0); count.decrementAndGet(); if(isFull){ LOG.info("唤醒生产者线程"); notifyAll(); } return task; } private boolean isFull(){ return count.get() == SIZE; } private boolean isEmpty(){ return count.get() == 0; }}

3. 生产者

public class Producer extends Thread{        private static final Logger LOG = LoggerFactory.getLogger(Producer.class);        private static AtomicInteger index = new AtomicInteger(0);        private TaskManager
taskManager; public Producer(TaskManager
taskManager){ this.setName("Thread-Producer-" + index.incrementAndGet()); this.taskManager = taskManager; } @Override public void run(){ while(true){ Task task = new Task(); try { taskManager.put(task); } catch (InterruptedException e) { LOG.info("停止生产"); return; } LOG.info("压入子弹" + task.getIndex()); } }}

4. 消费者

public class Customer extends Thread{        private static final Logger LOG = LoggerFactory.getLogger(Customer.class);        private static AtomicInteger index = new AtomicInteger(0);        private TaskManager
taskManager; public Customer(TaskManager
taskManager){ this.setName("Thread-Customer-" + index.incrementAndGet()); this.taskManager = taskManager; } @Override public void run(){ while(true){ Task task; try { task = taskManager.take(); } catch (InterruptedException e) { LOG.info("停止消费"); //可以将未消费的任务持久化 return; } LOG.info("射出子弹" + task.getIndex()); task.run(); } }}

5. 测试 

public class BootStrap {     public static void main(String[] args) throws InterruptedException {         //可以启动多个Producer及Customer,只要使用的是同一个TaskManager        TaskManager
taskManager = new TaskManager
(); Producer producer1 = new Producer(taskManager); Producer producer2 = new Producer(taskManager); Customer customer1 = new Customer(taskManager); Customer customer2 = new Customer(taskManager); Customer customer3 = new Customer(taskManager); producer1.start(); producer2.start(); customer1.start(); customer2.start(); customer3.start(); Thread.sleep(1); producer1.interrupt(); producer2.interrupt(); Thread.sleep(5); customer1.interrupt(); customer2.interrupt(); customer3.interrupt(); }}

 

转载于:https://www.cnblogs.com/shanhm1991/p/9905274.html

你可能感兴趣的文章
152. Maximum Product Subarray
查看>>
upupw : Apache Php5.5 的使用
查看>>
UBUNTU12.04下安装配置体验gnome3
查看>>
常用下载文件的公共方法
查看>>
java面试题4
查看>>
21个最佳jQuery插件推荐
查看>>
Webstorm9配置SASS编译环境
查看>>
SDN第四次上机作业
查看>>
mac下安装nginx并且利用nginx解决本地前端工程访问后端接口跨域问题
查看>>
NodeMCU入门(2):在线构建、刷入固件,上传代码
查看>>
U. Apache
查看>>
信号处理
查看>>
delphi 资源文件
查看>>
我想写程序#2 之 「两招(三支程序)就可以出师」
查看>>
索引和索引调整向导
查看>>
linux下的rz sz
查看>>
openfire 学习笔记--转自网易博客
查看>>
编译(树形DP)
查看>>
java微信支付异步回调接收参数
查看>>
test
查看>>