jdk-ConcurrentLinkedQueue(二)

来源:互联网 发布:c语言可以用string类吗 编辑:程序博客网 时间:2024/05/01 13:29

第一篇详细画出了在入队和出队时的操作,看的真的很费时,说实话,我看了好几遍才动手开始画队列变换的图,并且在画图时还时不时的修正了很多次。。。总结出,对于jdk源码的话,多看几遍总能看出作者的意图的,不要害怕看不懂,看不懂第一遍,看二遍,三遍。

这次的博客去看下此类中的其他一些方法,准备为将来的使用坐下基础。

succ方法,向后推进方法,可以看出获取的是当前节点的后继节点,比较了 p 和next是否相等,在第一篇博客分析时,发现在出队情况下,是有可能出现next指向自身的节点,出现这个节点,意味着出队执行成功,并且设置了新的head节点,head节点指向了下一个有效的队列头。

 final Node<E> succ(Node<E> p) {        Node<E> next = p.next;        return (p == next) ? head : next;    }


peek方法,跟出队操作很类似,获取当前head指向的节点,判读item是否为null

1. item 不为null,更新head指向,并返回当前item值。

2.item为 null,判断当前节点是否到达了尾部,如果是尾部的话,更新head节点指于此,如果不是尾部的话,判断是够指向自身,都不是的话,p节点后移,重新获取下一个节点的item值。peek方法总的来说是获取head节点之后第一个有效节点。

public E peek() {        restartFromHead:        for (;;) {            for (Node<E> h = head, p = h, q;;) {                E item = p.item;                if (item != null || (q = p.next) == null) {                    updateHead(h, p);                    return item;                }                else if (p == q)                    continue restartFromHead;                else                    p = q;            }        }    }
first方法。返回的是head节点之后的第一个不为null的有效节点的item值,可以看见,如果当前节点到达尾部的话,会更新一下head的值,并且会判断当前尾部节点的item是否是null,是的话返回空节点,不是的话返回有效节点
Node<E> first() {        restartFromHead:        for (;;) {            for (Node<E> h = head, p = h, q;;) {                boolean hasItem = (p.item != null);                if (hasItem || (q = p.next) == null) {                    updateHead(h, p);                    return hasItem ? p : null;                }                else if (p == q)                    continue restartFromHead;                else                    p = q;            }        }    }
isEmpty 字面意思判空。

如果head处的节点item值不为null,那么first会立即返回这个节点,立马知道这个队列不空。

如果first返回的是null的话,说明从head处读取到之后的节点都为null一直到最后的尾部节点,依然是null,才最终返回null。注意此处是从head节点开始读取的,head节点在出队操作中会不断变化。那么只有在这个队列全为null时,才会去遍历整个队列。

 public boolean isEmpty() {        return first() == null;    }
可以看见size方法并不适用于判空处理,它会循环整个队列,计算出count值,消耗极大,并且这个count的值也不是准确的,多线程情况下有可能不靠谱,需要我们手动去做同步,注意一下。
public int size() {        int count = 0;        for (Node<E> p = first(); p != null; p = succ(p))            if (p.item != null)                // Collection.size() spec says to max out                if (++count == Integer.MAX_VALUE)                    break;        return count;    }
contains方法,去队列中寻找是否包含这个item项的节点。跟size方法一样,使用succ方式去遍历,但是这个方法一样会出现数据不同步的情况。
public boolean contains(Object o) {        if (o == null) return false;        for (Node<E> p = first(); p != null; p = succ(p)) {            E item = p.item;            if (item != null && o.equals(item))                return true;        }        return false;    }

使用ConcurrentLinkedQueue实现生产者消费者went
public class TestConcurrentLinkedDeque {    public static void main(String[] args) {        ConcurrentLinkedQueue<Food> foods = new ConcurrentLinkedQueue<Food>();        final Provider provider = new Provider(foods);        final Customer customer = new Customer(foods);        for(int i = 0; i < 10; i ++){            new Thread(new Runnable() {                public void run() {                    provider.runP();                }            }).start();        }        for(int i = 0; i < 10; i ++){            new Thread(new Runnable() {                public void run() {                    customer.runC();                }            }).start();        }    }}

public class Provider {    private ConcurrentLinkedQueue<Food> foods;    /*采用原子Integer,可以完美解决多线程环境下数目的变换*/    private AtomicInteger num = new AtomicInteger();    public Provider(ConcurrentLinkedQueue<Food> foods) {        this.foods = foods;    }    public void runP() {        // TODO Auto-generated method stub        while (true) {            int index = num.incrementAndGet();            String name = "甜品  "+index+" 号";            try {                foods.offer(new Food(index, name));                System.out.println(Thread.currentThread()+"生产了第 "+ index + "号 食品: "+name + System.currentTimeMillis());                Thread.sleep(2000);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

public class Customer {    private ConcurrentLinkedQueue<Food> foods;    public Customer(ConcurrentLinkedQueue<Food> foods) {        this.foods = foods;    }    public void runC() {        // TODO Auto-generated method stub        while (true) {            try {                Food food = foods.poll();                if(food == null){                    System.err.println(Thread.currentThread()+ "消费失败,无数据生产出 " +System.currentTimeMillis());                }else {                    System.err.println(Thread.currentThread()+ "消费了第 "+food.getNum()+"食品 : " + food.getName()+System.currentTimeMillis());                    Thread.sleep(2000);                }            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

Thread[Thread-0,5,main]生产了第 1号 食品: 甜品  1 号1496710329448Thread[Thread-2,5,main]生产了第 2号 食品: 甜品  2 号1496710329448Thread[Thread-4,5,main]生产了第 3号 食品: 甜品  3 号1496710329449Thread[Thread-6,5,main]生产了第 4号 食品: 甜品  4 号1496710329449Thread[Thread-8,5,main]生产了第 5号 食品: 甜品  5 号1496710329449Thread[Thread-10,5,main]消费了第 1食品 : 甜品  1 号1496710329450Thread[Thread-12,5,main]消费了第 2食品 : 甜品  2 号1496710329450Thread[Thread-14,5,main]消费了第 3食品 : 甜品  3 号1496710329450Thread[Thread-16,5,main]消费了第 4食品 : 甜品  4 号1496710329451Thread[Thread-18,5,main]消费了第 5食品 : 甜品  5 号1496710329451Thread[Thread-11,5,main]消费了第 6食品 : 甜品  6 号1496710329451Thread[Thread-13,5,main]消费了第 7食品 : 甜品  7 号1496710329451Thread[Thread-15,5,main]消费了第 8食品 : 甜品  8 号1496710329451Thread[Thread-17,5,main]消费了第 9食品 : 甜品  9 号1496710329451Thread[Thread-19,5,main]消费了第 10食品 : 甜品  10 号1496710329452Thread[Thread-1,5,main]生产了第 6号 食品: 甜品  6 号1496710329451Thread[Thread-3,5,main]生产了第 7号 食品: 甜品  7 号1496710329451Thread[Thread-5,5,main]生产了第 8号 食品: 甜品  8 号1496710329451Thread[Thread-7,5,main]生产了第 9号 食品: 甜品  9 号1496710329451Thread[Thread-9,5,main]生产了第 10号 食品: 甜品  10 号1496710329451Thread[Thread-10,5,main]消费了第 12食品 : 甜品  12 号1496710331450Thread[Thread-14,5,main]消费了第 13食品 : 甜品  13 号1496710331450Thread[Thread-12,5,main]消费了第 11食品 : 甜品  11 号1496710331450Thread[Thread-18,5,main]消费了第 14食品 : 甜品  14 号1496710331451Thread[Thread-16,5,main]消费了第 15食品 : 甜品  15 号1496710331451Thread[Thread-11,5,main]消费了第 16食品 : 甜品  16 号1496710331451Thread[Thread-13,5,main]消费了第 17食品 : 甜品  17 号1496710331451Thread[Thread-15,5,main]消费了第 18食品 : 甜品  18 号1496710331451Thread[Thread-0,5,main]生产了第 11号 食品: 甜品  11 号1496710331448Thread[Thread-17,5,main]消费了第 19食品 : 甜品  19 号1496710331452Thread[Thread-2,5,main]生产了第 12号 食品: 甜品  12 号1496710331448Thread[Thread-19,5,main]消费了第 20食品 : 甜品  20 号1496710331452Thread[Thread-4,5,main]生产了第 13号 食品: 甜品  13 号1496710331449Thread[Thread-6,5,main]生产了第 14号 食品: 甜品  14 号1496710331449Thread[Thread-8,5,main]生产了第 15号 食品: 甜品  15 号1496710331449Thread[Thread-1,5,main]生产了第 16号 食品: 甜品  16 号1496710331451Thread[Thread-3,5,main]生产了第 17号 食品: 甜品  17 号1496710331451Thread[Thread-9,5,main]生产了第 18号 食品: 甜品  18 号1496710331451Thread[Thread-5,5,main]生产了第 19号 食品: 甜品  19 号1496710331451Thread[Thread-7,5,main]生产了第 20号 食品: 甜品  20 号1496710331451Thread[Thread-10,5,main]消费了第 21食品 : 甜品  21 号1496710333450Thread[Thread-12,5,main]消费了第 22食品 : 甜品  22 号1496710333450Thread[Thread-14,5,main]消费了第 23食品 : 甜品  23 号1496710333450Thread[Thread-16,5,main]消费了第 24食品 : 甜品  24 号1496710333451Thread[Thread-18,5,main]消费了第 25食品 : 甜品  25 号1496710333451Thread[Thread-11,5,main]消费了第 26食品 : 甜品  26 号1496710333451Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451Thread[Thread-15,5,main]消费了第 27食品 : 甜品  27 号1496710333451Thread[Thread-13,5,main]消费了第 28食品 : 甜品  28 号1496710333451Thread[Thread-0,5,main]生产了第 21号 食品: 甜品  21 号1496710333448Thread[Thread-2,5,main]生产了第 22号 食品: 甜品  22 号1496710333448Thread[Thread-4,5,main]生产了第 23号 食品: 甜品  23 号1496710333449Thread[Thread-6,5,main]生产了第 24号 食品: 甜品  24 号1496710333449Thread[Thread-8,5,main]生产了第 25号 食品: 甜品  25 号1496710333449Thread[Thread-3,5,main]生产了第 26号 食品: 甜品  26 号1496710333451Thread[Thread-1,5,main]生产了第 27号 食品: 甜品  27 号1496710333451Thread[Thread-9,5,main]生产了第 28号 食品: 甜品  28 号1496710333451Thread[Thread-5,5,main]生产了第 29号 食品: 甜品  29 号1496710333451Thread[Thread-7,5,main]生产了第 30号 食品: 甜品  30 号1496710333451Thread[Thread-17,5,main]消费了第 29食品 : 甜品  29 号1496710333452Thread[Thread-19,5,main]消费了第 30食品 : 甜品  30 号1496710333452Thread[Thread-0,5,main]生产了第 31号 食品: 甜品  31 号1496710335449Thread[Thread-2,5,main]生产了第 32号 食品: 甜品  32 号1496710335449Thread[Thread-4,5,main]生产了第 33号 食品: 甜品  33 号1496710335450Thread[Thread-8,5,main]生产了第 34号 食品: 甜品  34 号1496710335450Thread[Thread-6,5,main]生产了第 35号 食品: 甜品  35 号1496710335450Thread[Thread-3,5,main]生产了第 36号 食品: 甜品  36 号1496710335452Thread[Thread-1,5,main]生产了第 37号 食品: 甜品  37 号1496710335452Thread[Thread-9,5,main]生产了第 38号 食品: 甜品  38 号1496710335452Thread[Thread-5,5,main]生产了第 39号 食品: 甜品  39 号1496710335452Thread[Thread-7,5,main]生产了第 40号 食品: 甜品  40 号1496710335452Thread[Thread-10,5,main]消费了第 31食品 : 甜品  31 号1496710335451Thread[Thread-12,5,main]消费了第 32食品 : 甜品  32 号1496710335451Thread[Thread-14,5,main]消费了第 33食品 : 甜品  33 号1496710335451Thread[Thread-16,5,main]消费了第 34食品 : 甜品  34 号1496710335452Thread[Thread-18,5,main]消费了第 35食品 : 甜品  35 号1496710335452Thread[Thread-11,5,main]消费了第 36食品 : 甜品  36 号1496710335452Thread[Thread-13,5,main]消费了第 37食品 : 甜品  37 号1496710335452Thread[Thread-15,5,main]消费失败,无数据生产出 1496710335452Thread[Thread-15,5,main]消费了第 38食品 : 甜品  38 号1496710335452Thread[Thread-17,5,main]消费了第 39食品 : 甜品  39 号1496710335453Thread[Thread-19,5,main]消费了第 40食品 : 甜品  40 号1496710335453

实现方式和LinkBlobkedQueue类似

原创粉丝点击