手書き輻輳キュー、および全体の最適化プロセス

最初の2つは非常に不完全な輻輳キューであり、第三は、より完璧とみなされ、直接、第三ブロックされたキューを見ることができます。

まず、すべての混雑キュー:

locksupportを使用し、全体のプロセス、および操作の独自のリストを待ってから通知を実装します。
短所:入れて操作を取得し、ロックが共有されている実際には、取得することができますし、並列に入れ、put操作キューヘッドので、尾は、それが並列動作で取得し、ため、最適化の余地があります。

public class LinkedQueue<T> {

    // 维护一个数据节点双向链表的head和tail指针
    private Node tail;
    private Node head;
    // 维护一个get线程节点双向链表的head和tail指针
    private ThreadNode getHeadThread;
    private ThreadNode getTailThread;
    // 维护一个put线程节点双向链表的head和tail指针
    private ThreadNode putHeadThread;
    private ThreadNode putTailThread;
    private Integer size;
    private Integer count;
    // put锁
    ReentrantLock lock = new ReentrantLock();


    public LinkedQueue(Integer size) {
        this.size = size;
        this.count = 0;
        this.tail = new Node();
        this.head = new Node();
        head.next = tail;
        tail.prev = head;
        getHeadThread = new ThreadNode();
        getTailThread = new ThreadNode();
        getHeadThread.next = getTailThread;
        getTailThread.prev = getHeadThread;
        putHeadThread = new ThreadNode();
        putTailThread = new ThreadNode();
        putHeadThread.next = putTailThread;
        putTailThread.prev = putHeadThread;

    }


    // 存储元素的
    class Node {
        public T item;
        public Node next;
        public Node prev;

        public Node(T item, Node next, Node prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public Node() {}
    }

    class ThreadNode {
        public Thread thread;
        public ThreadNode next;
        public ThreadNode prev;

        public ThreadNode() {}

        public ThreadNode(Thread thread, ThreadNode next, ThreadNode prev) {
            this.thread = thread;
            this.next = next;
            this.prev = prev;
        }
    }

    public void put(T item) {
        lock.lock();
        // 容量已经满了
        if (size.equals(count)) {
            Thread thread = Thread.currentThread();
            ThreadNode temp = putHeadThread.next;
            ThreadNode threadNode = new ThreadNode(thread, temp, putHeadThread);
            temp.prev = threadNode;
            putHeadThread.next = threadNode;
            lock.unlock();
            LockSupport.park();
            this.put(item);
            return;
        }
        Node temp = head.next;
        // 把node加入head的下一个节点,维护一个双链表结构
        Node node = new Node(item, temp, head);
        head.next = node;
        temp.prev = node;
        count++;
        if (getTailThread.prev != getHeadThread) {
            ThreadNode prev = getTailThread.prev;
            ThreadNode t = prev.prev;
            getTailThread.prev = t;
            t.next = getTailThread;
            Thread thread = prev.thread;
            LockSupport.unpark(thread);
        }
        lock.unlock();
    }

    public T get() {
        lock.lock();
        Node prev = tail.prev;
        if (prev == head) {
            // 队列为空,堵塞
            Thread thread = Thread.currentThread();
            ThreadNode temp = getHeadThread.next;
            ThreadNode threadNode = new ThreadNode(thread, temp, getHeadThread);
            temp.prev = threadNode;
            getHeadThread.next = threadNode;
            lock.unlock();
            LockSupport.park();
            return this.get();
        }
        Node temp = prev.prev;
        tail.prev = temp;
        temp.next = tail;
        count--;
        // 唤醒put的线程
        if (putTailThread.prev != putHeadThread) {
            ThreadNode prevPut = putTailThread.prev;
                ThreadNode t = prevPut.prev;
                putTailThread.prev = t;
                t.next = putTailThread;
                Thread thread = prevPut.thread;
                LockSupport.unpark(thread);
        }
        lock.unlock();
        return prev.item;
    }

}

テストカテゴリ:それはgetおよびput同期シリアルですので、ノー並行性の問題、何の問題をテストしていないのは簡単です

public class Provider {

    LinkedQueue<Integer> linkedQueue = new LinkedQueue<>(3);
    AtomicInteger putNum = new AtomicInteger();
    long start;

    public void put() {
        for (int i = 0; i < 1000; i++) {
            int andIncrement = putNum.getAndIncrement();
            linkedQueue.put(andIncrement);
            System.out.println("put in " + Thread.currentThread().getName() + " " + andIncrement
                    + " endTime:" + (System.currentTimeMillis() - start));
        }
    }

    public void get() {
        while (true) {
            Integer integer = linkedQueue.get();
            System.out.println(Thread.currentThread().getName() + " " + integer
                    + " endTime:" + (System.currentTimeMillis() - start));
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Provider provider = new Provider();
        provider.start = System.currentTimeMillis();
        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                provider.put();
            }).start();
        }
        System.out.println("get");
        for (int i = 0; i < 50; i++) {
            new Thread(() -> provider.get()).start();
        }
//        Thread.sleep(5000);
//        System.out.println("ok");
//        provider.put();
    }

}

二混雑キュー:
上記とlocksupportリストの代わりに条件。
それは非常にきれいに見えますが、実際には非効率的。
短所:1以上、同期キューです。
2.signalはsignallで、毎回のウェイクアップすべての待機をした後、スレッドは、待ち時間を入力し、無駄な作業の多くを行う、私たちはされて目を覚ますまで待って、リストをlinkedblockする条件リスト、待ちリストの状態になりますlinkedblockですリストは、この役に立たない多くの作業を行います。


public class LinkedQueue2<T> {

    // 维护一个数据节点双向链表的head和tail指针
    private Node tail;
    private Node head;
    private Integer size;
    private Integer count;
    // put锁
    ReentrantLock lock = new ReentrantLock();
    Condition getCondition = lock.newCondition();
    Condition putCondition = lock.newCondition();


    public LinkedQueue2(Integer size) {
        this.size = size;
        this.count = 0;
        this.tail = new LinkedQueue2.Node();
        this.head = new LinkedQueue2.Node();
        head.next = tail;
        tail.prev = head;
    }


    // 存储元素的
    class Node {
        public T item;
        public LinkedQueue2.Node next;
        public LinkedQueue2.Node prev;

        public Node(T item, LinkedQueue2.Node next, LinkedQueue2.Node prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public Node() {}
    }

    public void put(T item) throws InterruptedException {
        lock.lock();
        // 容量已经满了
        if (size.equals(count)) {
            putCondition.await();
        }
        LinkedQueue2.Node temp = head.next;
        // 把node加入head的下一个节点,维护一个双链表结构
        LinkedQueue2.Node node = new LinkedQueue2.Node(item, temp, head);
        head.next = node;
        temp.prev = node;
        count++;
        if (count == 0) {
           getCondition.signalAll();
        }
        lock.unlock();
    }

    public T get() throws InterruptedException {
        lock.lock();
        // 队列为空,堵塞
        if (size == 0) {
            getCondition.await();
        }
        Node temp = tail.prev;
        tail.prev = temp;
        temp.next = tail;
        // 唤醒put的线程
        if (size.equals(count)) {
           putCondition.signalAll();
        }
        count--;
        lock.unlock();
        return temp.item;
    }
}

テスト

public class LinkedQueue2<T> {

    // 维护一个数据节点双向链表的head和tail指针
    private Node tail;
    private Node head;
    private Integer size;
    private Integer count;
    // put锁
    ReentrantLock lock = new ReentrantLock();
    Condition getCondition = lock.newCondition();
    Condition putCondition = lock.newCondition();


    public LinkedQueue2(Integer size) {
        this.size = size;
        this.count = 0;
        this.tail = new LinkedQueue2.Node();
        this.head = new LinkedQueue2.Node();
        head.next = tail;
        tail.prev = head;
    }


    // 存储元素的
    class Node {
        public T item;
        public LinkedQueue2.Node next;
        public LinkedQueue2.Node prev;

        public Node(T item, LinkedQueue2.Node next, LinkedQueue2.Node prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public Node() {}
    }

    public void put(T item) throws InterruptedException {
        lock.lock();
        // 容量已经满了
        if (size.equals(count)) {
            putCondition.await();
        }
        LinkedQueue2.Node temp = head.next;
        // 把node加入head的下一个节点,维护一个双链表结构
        LinkedQueue2.Node node = new LinkedQueue2.Node(item, temp, head);
        head.next = node;
        temp.prev = node;
        count++;
        if (count == 0) {
           getCondition.signalAll();
        }
        lock.unlock();
    }

    public T get() throws InterruptedException {
        lock.lock();
        // 队列为空,堵塞
        if (size == 0) {
            getCondition.await();
        }
        Node temp = tail.prev;
        tail.prev = temp;
        temp.next = tail;
        // 唤醒put的线程
        if (size.equals(count)) {
           putCondition.signalAll();
        }
        count--;
        lock.unlock();
        return temp.item;
    }
}

第三混雑キュー:
ソースコードLinkedBlockQueue政策的含意。
1、問題を解決し、同時実行を入れてもらうため、取得し、何の並行性の問題を入れないように、単一リンクリストを使用して。取得と並行して置くようにし、取得し、2つのロックを置きます。
2ので、自分でウェイクアップスレッドをゲットするには、自分のウェイクアップを取得し、シリアライズ、まれロック競争を入れて糸を入れて置きます。
、whileループを使用してそのような待機操作など多くの詳細は、待ち時間を短縮し、スレッドに頻繁な切り替えを通知し、余分な通話や他の同時実行の問題を通知するために注意を払う512回スピン、単鎖が頭から取得します、3があり、詳細はコードのコメントを参照してください。

public class LinkedQueue3<T> {

    ReentrantLock putLock = new ReentrantLock();
    ReentrantLock getLock = new ReentrantLock();

    private Node tail;
    private Node head;

    private final Integer CAPACITY;

    private AtomicInteger size;

    Condition putCondition = putLock.newCondition();
    Condition getCondition = getLock.newCondition();


    // 存储元素的
    class Node {
        public T item;
        public Node next;
        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
        public Node() {}
    }

    public LinkedQueue3(Integer capacity) {
        CAPACITY = capacity;
        this.size = new AtomicInteger();
        this.head = this.tail = new Node();
    }

    public void put(T item) throws InterruptedException {
        putLock.lock();
        // 容量已经满了
        // 这里为什么要while?因为被唤醒,不一定就立即获得锁
        // 如果被唤醒没有获得锁,被别的put线程获得锁了,然后
        // 马上添加了一个元素,则被唤醒的线程,获得锁之后,则
        // 容量已经满了,所以需要while继续等待
        // 所以对于多线程wait操作,一定不要忘了wait操作用while循环做
        while (size.get() == CAPACITY) {
            /*
  如果在这里唤醒,就会出问题,因为,容量满了之后第一个put操作,
  唤醒了一个get线程,那个get线程还没有get元素,则又一个put操作,又
  会唤醒一个get线程,则如此,会唤醒很多个get线程,然后很多个get线程去
  争取getlock,一个get线程争取到了,size-1,又唤醒了一个get线程,
  因为size=capacity,又唤醒了一个put线程,put操作还没来得及put,
  get操作已经get完了,
  最后,size为0,则所有get操作堵塞,而且唤醒了多个put操作,
  也就是说,最后,put线程和get线程都醒了,
signal就没有用了,然后signal后await,最后都堵塞了,没人唤醒了

//对我们的启示是,signal操作,不要有多个地方都signal,一个地方
就够了,多个地方,很容易出几个回合之后,唤醒多个线程的并发问题
  */
            // 唤醒get
//            getLock.lock();
//            getCondition.signal();
//            getLock.unlock();

// 当想进行await操作的时候,先自旋512次,减少,高并发下频繁await和notify的线程切换,设计思想来源于sequenceQueue源代码
            for(int i = 0; i < 512; i++){
               if(size.get() != CAPACITY){
                   break;
               }else{
                   if(i == 512){
                       putCondition.await();
                   }
               }
            }
        }
        // 入队
        tail = tail.next = new Node(item, null);
        int beforeSize = size.getAndIncrement();
        if(beforeSize + 1 < CAPACITY){
            putCondition.signal();
        }
        putLock.unlock();
        // 如果入队前,队列为null,则唤醒get
        if(beforeSize == 0){
            getLock.lock();
            getCondition.signal();
            getLock.unlock();
        }
    }

    public T get() throws InterruptedException {
        getLock.lock();
        // 队列为空,堵塞
        while (size.get() == 0) {
            // 唤醒put操作
//            putLock.lock();
//            putCondition.signal();
//            putLock.unlock();
            getCondition.await();
        }
        // 出队
        Node h = head;
        Node first = head.next;
        h.next = h;
        head = first;
        T value = head.item;
        head.item = null;
        // 只能移除head元素,然后把head的下一个节点变成head,而不是,
        // 这样,直接移除head的下一个元素,否则head的下一个元素可能为tail,不能把tail移除了,而且还有其他问题
//        Node node = head.next;
//        head.next = node.next;
//        node.next = null;
//        T value = node.item;
        int beforeSize = size.getAndDecrement();
        // 还有元素
        if(beforeSize - 1 != 0){
            getCondition.signal();

        }
        getLock.unlock();
        // 出队之前,容量是满的
        if (beforeSize == CAPACITY) {
            putLock.lock();
            putCondition.signal();
            putLock.unlock();
        }
        return value;
    }

}

テストコード:

public class Provider3 {

    LinkedQueue3<Integer> linkedQueue = new LinkedQueue3<>(3);
    AtomicInteger putNum = new AtomicInteger();
    long start;

    public void put() throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            int andIncrement = putNum.getAndIncrement();
            linkedQueue.put(andIncrement);
            System.out.println("put in " + Thread.currentThread().getName() + " " + andIncrement
                    + " endTime:" + (System.currentTimeMillis() - start));
        }
    }

    public void get() throws InterruptedException {
        while (true) {
            Integer integer = linkedQueue.get();
            System.out.println(Thread.currentThread().getName() + " " + integer
                    + " endTime:" + (System.currentTimeMillis() - start));
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Provider3 provider = new Provider3();
        provider.start = System.currentTimeMillis();
        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                try {
                    provider.put();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        System.out.println("get");
        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                try {
                    provider.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
//        Thread.sleep(5000);
//        System.out.println("ok");
//        provider.put();
    }


}

コードパス:https://gitee.com/wuliaozhiyuan/private.git(独自)

ます。https://www.jianshu.com/p/a6a864c9f877で再現

おすすめ

転載: blog.csdn.net/weixin_34327761/article/details/91202639