jdk-ConcurrentLinkedQueue(二)

第一篇详细画出了在入队和出队时的操作,看的真的很费时,说实话,我看了好几遍才动手开始画队列变换的图,并且在画图时还时不时的修正了很多次。。。总结出,对于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 号1496710329448
Thread[Thread-2,5,main]生产了第 2号 食品: 甜品  2 号1496710329448
Thread[Thread-4,5,main]生产了第 3号 食品: 甜品  3 号1496710329449
Thread[Thread-6,5,main]生产了第 4号 食品: 甜品  4 号1496710329449
Thread[Thread-8,5,main]生产了第 5号 食品: 甜品  5 号1496710329449
Thread[Thread-10,5,main]消费了第 1食品 : 甜品  1 号1496710329450
Thread[Thread-12,5,main]消费了第 2食品 : 甜品  2 号1496710329450
Thread[Thread-14,5,main]消费了第 3食品 : 甜品  3 号1496710329450
Thread[Thread-16,5,main]消费了第 4食品 : 甜品  4 号1496710329451
Thread[Thread-18,5,main]消费了第 5食品 : 甜品  5 号1496710329451
Thread[Thread-11,5,main]消费了第 6食品 : 甜品  6 号1496710329451
Thread[Thread-13,5,main]消费了第 7食品 : 甜品  7 号1496710329451
Thread[Thread-15,5,main]消费了第 8食品 : 甜品  8 号1496710329451
Thread[Thread-17,5,main]消费了第 9食品 : 甜品  9 号1496710329451
Thread[Thread-19,5,main]消费了第 10食品 : 甜品  10 号1496710329452
Thread[Thread-1,5,main]生产了第 6号 食品: 甜品  6 号1496710329451
Thread[Thread-3,5,main]生产了第 7号 食品: 甜品  7 号1496710329451
Thread[Thread-5,5,main]生产了第 8号 食品: 甜品  8 号1496710329451
Thread[Thread-7,5,main]生产了第 9号 食品: 甜品  9 号1496710329451
Thread[Thread-9,5,main]生产了第 10号 食品: 甜品  10 号1496710329451
Thread[Thread-10,5,main]消费了第 12食品 : 甜品  12 号1496710331450
Thread[Thread-14,5,main]消费了第 13食品 : 甜品  13 号1496710331450
Thread[Thread-12,5,main]消费了第 11食品 : 甜品  11 号1496710331450
Thread[Thread-18,5,main]消费了第 14食品 : 甜品  14 号1496710331451
Thread[Thread-16,5,main]消费了第 15食品 : 甜品  15 号1496710331451
Thread[Thread-11,5,main]消费了第 16食品 : 甜品  16 号1496710331451
Thread[Thread-13,5,main]消费了第 17食品 : 甜品  17 号1496710331451
Thread[Thread-15,5,main]消费了第 18食品 : 甜品  18 号1496710331451
Thread[Thread-0,5,main]生产了第 11号 食品: 甜品  11 号1496710331448
Thread[Thread-17,5,main]消费了第 19食品 : 甜品  19 号1496710331452
Thread[Thread-2,5,main]生产了第 12号 食品: 甜品  12 号1496710331448
Thread[Thread-19,5,main]消费了第 20食品 : 甜品  20 号1496710331452
Thread[Thread-4,5,main]生产了第 13号 食品: 甜品  13 号1496710331449
Thread[Thread-6,5,main]生产了第 14号 食品: 甜品  14 号1496710331449
Thread[Thread-8,5,main]生产了第 15号 食品: 甜品  15 号1496710331449
Thread[Thread-1,5,main]生产了第 16号 食品: 甜品  16 号1496710331451
Thread[Thread-3,5,main]生产了第 17号 食品: 甜品  17 号1496710331451
Thread[Thread-9,5,main]生产了第 18号 食品: 甜品  18 号1496710331451
Thread[Thread-5,5,main]生产了第 19号 食品: 甜品  19 号1496710331451
Thread[Thread-7,5,main]生产了第 20号 食品: 甜品  20 号1496710331451
Thread[Thread-10,5,main]消费了第 21食品 : 甜品  21 号1496710333450
Thread[Thread-12,5,main]消费了第 22食品 : 甜品  22 号1496710333450
Thread[Thread-14,5,main]消费了第 23食品 : 甜品  23 号1496710333450
Thread[Thread-16,5,main]消费了第 24食品 : 甜品  24 号1496710333451
Thread[Thread-18,5,main]消费了第 25食品 : 甜品  25 号1496710333451
Thread[Thread-11,5,main]消费了第 26食品 : 甜品  26 号1496710333451
Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451
Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451
Thread[Thread-15,5,main]消费失败,无数据生产出 1496710333451
Thread[Thread-15,5,main]消费了第 27食品 : 甜品  27 号1496710333451
Thread[Thread-13,5,main]消费了第 28食品 : 甜品  28 号1496710333451
Thread[Thread-0,5,main]生产了第 21号 食品: 甜品  21 号1496710333448
Thread[Thread-2,5,main]生产了第 22号 食品: 甜品  22 号1496710333448
Thread[Thread-4,5,main]生产了第 23号 食品: 甜品  23 号1496710333449
Thread[Thread-6,5,main]生产了第 24号 食品: 甜品  24 号1496710333449
Thread[Thread-8,5,main]生产了第 25号 食品: 甜品  25 号1496710333449
Thread[Thread-3,5,main]生产了第 26号 食品: 甜品  26 号1496710333451
Thread[Thread-1,5,main]生产了第 27号 食品: 甜品  27 号1496710333451
Thread[Thread-9,5,main]生产了第 28号 食品: 甜品  28 号1496710333451
Thread[Thread-5,5,main]生产了第 29号 食品: 甜品  29 号1496710333451
Thread[Thread-7,5,main]生产了第 30号 食品: 甜品  30 号1496710333451
Thread[Thread-17,5,main]消费了第 29食品 : 甜品  29 号1496710333452
Thread[Thread-19,5,main]消费了第 30食品 : 甜品  30 号1496710333452
Thread[Thread-0,5,main]生产了第 31号 食品: 甜品  31 号1496710335449
Thread[Thread-2,5,main]生产了第 32号 食品: 甜品  32 号1496710335449
Thread[Thread-4,5,main]生产了第 33号 食品: 甜品  33 号1496710335450
Thread[Thread-8,5,main]生产了第 34号 食品: 甜品  34 号1496710335450
Thread[Thread-6,5,main]生产了第 35号 食品: 甜品  35 号1496710335450
Thread[Thread-3,5,main]生产了第 36号 食品: 甜品  36 号1496710335452
Thread[Thread-1,5,main]生产了第 37号 食品: 甜品  37 号1496710335452
Thread[Thread-9,5,main]生产了第 38号 食品: 甜品  38 号1496710335452
Thread[Thread-5,5,main]生产了第 39号 食品: 甜品  39 号1496710335452
Thread[Thread-7,5,main]生产了第 40号 食品: 甜品  40 号1496710335452
Thread[Thread-10,5,main]消费了第 31食品 : 甜品  31 号1496710335451
Thread[Thread-12,5,main]消费了第 32食品 : 甜品  32 号1496710335451
Thread[Thread-14,5,main]消费了第 33食品 : 甜品  33 号1496710335451
Thread[Thread-16,5,main]消费了第 34食品 : 甜品  34 号1496710335452
Thread[Thread-18,5,main]消费了第 35食品 : 甜品  35 号1496710335452
Thread[Thread-11,5,main]消费了第 36食品 : 甜品  36 号1496710335452
Thread[Thread-13,5,main]消费了第 37食品 : 甜品  37 号1496710335452
Thread[Thread-15,5,main]消费失败,无数据生产出 1496710335452
Thread[Thread-15,5,main]消费了第 38食品 : 甜品  38 号1496710335452
Thread[Thread-17,5,main]消费了第 39食品 : 甜品  39 号1496710335453
Thread[Thread-19,5,main]消费了第 40食品 : 甜品  40 号1496710335453

实现方式和LinkBlobkedQueue类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值