当前位置:编程学习 > JAVA >>

Java线程(篇外篇):阻塞队列BlockingQueue

 BlockingQueue最终会有四种状况,抛出异常、返回特殊值、阻塞、超时,下表总结了这些方法:

  抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用
       BlockingQueue是个接口,有如下实现类:
       1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
       2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。

       3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。

       4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。

       下面使用ArrayBlockQueue来实现之前实现过的生产者消/费者模式,代码如下:

[java] 
/** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */ 
public class BigPlate { 
 
    /** 装鸡蛋的盘子,大小为5 */ 
    private BlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(5); 
     
    /** 放鸡蛋 */ 
    public void putEgg(Object egg) { 
        try { 
            eggs.put(egg);// 向盘子末尾放一个鸡蛋,如果盘子满了,当前线程阻塞 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        System.out.println("放入鸡蛋"); 
    } 
     
    /** 取鸡蛋 */ 
    public Object getEgg() { 
        Object egg = null; 
        try { 
            egg = eggs.take();// 从盘子开始取一个鸡蛋,如果盘子空了,当前线程阻塞 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        System.out.println("拿到鸡蛋"); 
        return egg; 
    } 
     
    /** 放鸡蛋线程 */ 
    static class AddThread extends Thread { 
        private BigPlate plate; 
        private Object egg = new Object(); 
 
        public AddThread(BigPlate plate) { 
            this.plate = plate; 
        } 
 
        public void run() { 
            plate.putEgg(egg); 
        } 
    } 
 
    /** 取鸡蛋线程 */ 
    static class GetThread extends Thread { 
        private BigPlate plate; 
 
        public GetThread(BigPlate plate) { 
            this.plate = plate; 
        } 
 
        public void run() { 
            plate.getEgg(); 
        } 
    } 
     
    public static void main(String[] args) { 
        BigPlate plate = new BigPlate(); 
        // 先启动10个放鸡蛋线程 
        for(int i = 0; i < 10; i++) { 
            new Thread(new AddThread(plate)).start(); 
        } 
        // 再启动10个取鸡蛋线程 
        for(int i = 0; i < 10; i++) { 
            new Thread(new GetThread(plate)).start(); 
        } 
    } 

       执行结果:
[plain] 
放入鸡蛋 
放入鸡蛋 
放入鸡蛋 
放入鸡蛋 
放入鸡蛋 
拿到鸡蛋 
放入鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
放入鸡蛋 
放入鸡蛋 
放入鸡蛋 
拿到鸡蛋 
放入鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
拿到鸡蛋 
       从结果看,启动10个放鸡蛋线程和10个取鸡蛋线程,钱5个放入鸡蛋的线程成功执行,到第6个,发现盘子满了,阻塞住,这时切换到取鸡蛋线程执行,成功实现了生产者/消费者模式

补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,