阻塞队列实现--生产消费模型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/JY_He/article/details/52742825

生产消费模型是多线程安全的典型例子,当初实现的时候使用的是一个数组或者队列,加上synchronized关键字,代码量比较多,后来学习了阻塞队列,发现使用阻塞队列来实现代码简洁不少,这样在面试的时候,面试官需要你实现一个生产消费模型也会好写一些,下面我给出原始和阻塞队列实现的代码供参考:

1.原始实现

package Concurrent;

import java.util.PriorityQueue;
import java.util.Queue;

public class TestObjProCon {
    //定义队列的长度
    private int queueSize=10;
    
  //定义一个队列,这里使用的是优先队列PriorityQueue
    private Queue<Integer> queue=new PriorityQueue<Integer>(queueSize);
    
    public static void main(String[] args){
        TestObjProCon test=new TestObjProCon();
        Consumer c=test.new Consumer();
        Productor p=test.new Productor();
        
        c.start();
        p.start();
    }
    
     //消费者类
     class Consumer extends Thread{
         @Override
         public void run(){
             comsume();
         }

        private void comsume() {
           //使用一个while循环进行监听
            while(true){
                //同步队列
               synchronized (queue) {
                //判断队列内部元素个数,是否为0,为0等待,否则唤醒其他队列
               while(queue.size()==0){
                    try{
                        System.out.println("队列为空,不能取,请等待");
                        //调用wait方法,使取的队列进入阻塞
                        queue.wait();
                        
                        //调用wait方法后,线程中断抛出InterruptedException执行catch语句
                    }catch(InterruptedException e){
                        e.printStackTrace();
                        //并唤醒生产队列,即切换队列
                        queue.notify();
                    }
                }
                //若不为空,则可以进行consume
                //poll()每次都是移走队首元素
                queue.poll();
                //并唤醒生成线程,因为poll一次代表取了一次,即可以继续生产
                queue.notify();
                System.out.println("队列剩余的元素个数为:"+queue.size());
            }
           }
        }
     }
     
     //生产者类
     class Productor extends Thread{
         public void run(){
             produce();
         }
     }

    public void produce() {
       while(true){
           //同步队列
           synchronized (queue) {
               while(queue.size()==queueSize){
                   try{
                       System.out.println("队列已经满了,不能继续生产了");
                       queue.wait();//使生产队列进入阻塞
                   }catch(InterruptedException e){
                       e.printStackTrace();
                       queue.notify();//唤醒消费队列
                   }
                   
               }
               //否则可以继续生产
               queue.offer(1);//调用offer方法,每次插入一个元素
               queue.notify();//插入一个元素后即可以唤醒消费线程,执行消费
               System.out.println("此时队列里面的元素为:"+queue.size());
        }
       }
    }
}

2.阻塞队列实现:

package Concurrent;


import java.util.concurrent.PriorityBlockingQueue;

public class TestPriorityBlockingQueue {
    private int queueSize=10;
    private PriorityBlockingQueue<Integer> queue=new PriorityBlockingQueue<Integer>(queueSize);
    
    public static void main(String[] agrs){
        TestPriorityBlockingQueue test=new TestPriorityBlockingQueue();
        Consumer c=test.new Consumer();
        Productor p=test.new Productor();
        
        c.start();
        p.start();
    }
    
    class Consumer extends Thread{
        @Override
        public void run(){
            //重写run方法,在run方法中写自己的线程代码和相应方法
            comsume();
        }

        private void comsume() {
            //仍需要监听,而简化的是不需要使用synchronized同步锁了
            while(true){
                try{
                    //内部take已经实现了lock机制
                    queue.take();
                    System.out.println("队列元素剩余");
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }
    
    class Productor extends Thread{
        @Override
        public void run(){
            produce();
        }

        private void produce() {
            while(true){
                try {
                    //内部已经实现Lock机制,不要自己使用Synchronized和wait,notify
                    queue.put(1);
                } catch (NullPointerException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这里我简单说一下:PriorityBlockingQueue优先阻塞队列,take方法和put方法内部已经实现锁机制,采用的是ReentrantLock,内部已经实现Lock机制,不要自己使用Synchronized和wait,notify进行线程间通信,下面是相应的源码:

take:

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = dequeue()) == null)
                notEmpty.await();
        } finally {
            lock.unlock();
        }
        return result;
    }
put:

public void put(E e) {
        offer(e); // never need to block
    }
public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);
        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftUpComparable(n, e, array);
            else
                siftUpUsingComparator(n, e, array, cmp);
            size = n + 1;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }






猜你喜欢

转载自blog.csdn.net/JY_He/article/details/52742825