使用wait-notify实现生产消费模式

公司的一道考试题:设计一个符合生产者和消费者问题的程序。对一个对象(枪膛)进行操作,其最大容量是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<T extends Runnable> {
 
    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<T> taskList = new LinkedList<T>();
 
    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<Task> taskManager;
    
    public Producer(TaskManager<Task> 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<Task> taskManager;
    
    public Customer(TaskManager<Task> 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<Task> taskManager = new TaskManager<Task>();
        
        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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值