4.2 java併發容器 concurrentSkipListMap、concurrentSkipListSet、寫時複製容器、阻塞隊列、延時訂單的實現

一、concurrentSkipListMap、concurrentSkipListSet

concurrentSkipListMap、concurrentSkipListSet是兩個有序的容器,可以理解爲是treeMap和treeSet的併發版本
skipList是一種跳錶,是以空間換時間的一種機制,數據結構如下圖所顯示
在這裏插入圖片描述

2、concurrentLinkedQueue

無界非阻塞隊列, linkedList的併發版本

3.寫時複製容器:copyOnWriteArrayList、copyOnWriteArraySet

  • 寫時複製的概念
    當有寫操作時,將原有容器copy一份進行操作,然後將舊容器的指針指向新的容器。所有的讀操作都是在舊容器上進行的操作。讀寫都不進行加鎖

  • 數據一致性問題、只能保證最終一致性
    寫線程在新的容器中寫數據時,讀線程是無法看到的,因爲操作的是不同的容器,不能保證實時的可見行,只能被保證最終的一致性

  • 內存佔用問題
    寫入數據的時候容器的全部對象都要進行一份拷貝

  • 適合場景
    讀多寫少的操作場景,比如(白名單、黑名單、商品類目的更新)舉例:百度搜索引擎有許多敏感詞,這些詞彙每天都會有大量的讀操作,但是寫操作確實很少的,可能一天有時候都會寫不到一次,使用寫時複製容器這時候的效率是很高的

4、阻塞隊列

  • 概念、生產者消費者模式
    生產者消費者模式如果消費者和生產者的能力不匹配時,比如消費者的處理速度要高於生產者的生產速度,這是消費者就需要等待生產者去生產數據,然後再進行消費,阻塞隊列就是幹這事的。生產者往隊列中加數據,消費者讀數據,當容器中爲空時消費者阻塞等待,當容器滿的時候,生產者阻塞等待

  • 方法
    在這裏插入圖片描述

  • 常用的阻塞隊列辨析
    1⃣️ArrayBlockingQueue:由數組結構組成的有界阻塞隊列
    按照先進先出的規則、需要指定初始化容器大小、生產者消費者使用同一把鎖
    2⃣️LinkedBlockingQueue:由鏈表結構組成的有界阻塞隊列
    按照先進先出的規則、可以不設定初始大小,使用兩把鎖
    3⃣️PriorityBlockingQueue:支持優先級排序的無界阻塞隊列
    默認按照自然順序排序,否則需要重寫compareTo方法,或者初始化時指定比較器comparator
    4⃣️DelayQueue:使用優先級隊列實現的無界阻塞隊列
    支持延遲獲取元素的阻塞隊列,需要實現Delayed接口(超時緩存,訂單到期、限時支付)
    5⃣️SynchronousQueue:不存儲元素的阻塞隊列
    每一個put操作都要等待take操作,如果沒有消費者來進行take,則put操作需要阻塞
    6⃣️LinkedTransferQueue:由鏈表結構組成的無界阻塞隊列
    transfer():如果有消費者等待take,直接將數據給消費者,不插入隊列,消費者消費了之後當前方法纔會返回。
    tryTransfer():無論消費者是否接收都會立即返回
    7⃣️LinkedBlockingDeque:鏈表組成的雙向阻塞隊列 可以從隊頭和隊尾進行操作,效率更高,可實現工作密取

  • 使用阻塞隊列-----實現一個延時訂單

package cn.enjoy.controller.thread.DelayQueue;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * @author:wangle
 * @description:存放到隊列的元素、延時隊列
 * @version:V1.0
 * @date:2020-04-04 23:16
 **/
public class DelayQueueValue<T> implements Delayed {

    //到期時間、單元毫秒
    private Long activeTime;

    private T data;

    public DelayQueueValue(Long activeTime,T data){
        this.data = data;
        this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime,TimeUnit.MILLISECONDS)+System.nanoTime();
    }

    public Long getActiveTime(){
        return activeTime;
    }

    public T getData(){
        return data;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.activeTime-System.nanoTime(),TimeUnit.NANOSECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        Long d = getDelay(TimeUnit.NANOSECONDS)-o.getDelay(TimeUnit.NANOSECONDS);
        return d==0?0:(d>0?1:-1);
    }
}
package cn.enjoy.controller.thread.DelayQueue;

/**
 * @author:wangle
 * @description:訂單類
 * @version:V1.0
 * @date:2020-04-04 23:29
 **/
public class Order {

    //訂單name
    private final String name;

    public Order(String name){
        this.name=name;
    }

    public String getName(){
        return name;
    }

}
package cn.enjoy.controller.thread.DelayQueue;

import java.util.concurrent.DelayQueue;

/**
 * @author:wangle
 * @description:生產者
 * @version:V1.0
 * @date:2020-04-04 23:32
 **/
public class provider extends Thread{

    private DelayQueue<DelayQueueValue<Order>> delayQueue;

    public provider(DelayQueue<DelayQueueValue<Order>> delayQueue){
        this.delayQueue = delayQueue;
    }

    @Override
    public void run(){

        Order order = new Order("淘寶");
        DelayQueueValue<Order> delayQueueValue = new DelayQueueValue<Order>(5000L,order);
        delayQueue.offer(delayQueueValue);
        System.out.println("淘寶5秒後到期");

        Order orderLast = new Order("京東");
        DelayQueueValue<Order> delayQueueValueLast = new DelayQueueValue<Order>(8000L,orderLast);
        delayQueue.offer(delayQueueValueLast);
        System.out.println("京東8秒後到期");
    }
}
package cn.enjoy.controller.thread.DelayQueue;

import java.util.concurrent.DelayQueue;

/**
 * @author:wangle
 * @description:消費者
 * @version:V1.0
 * @date:2020-04-04 23:40
 **/
public class consumer extends Thread {

    private DelayQueue<DelayQueueValue<Order>> delayQueue;

    public consumer(DelayQueue<DelayQueueValue<Order>> delayQueue){
        this.delayQueue = delayQueue;
    }

    public void run(){
        while(true){
            try{
                DelayQueueValue<Order> delayQueueValue = delayQueue.take();
                Order order = delayQueueValue.getData();
                System.out.println(order.getName()+"到期了");
            }catch (InterruptedException e){
                //TODO deal
            }
        }
    }

}
package cn.enjoy.controller.thread.DelayQueue;

import java.util.concurrent.DelayQueue;

/**
 * @author:wangle
 * @description:
 * @version:V1.0
 * @date:2020-04-04 23:44
 **/
public class TestCase {

    public static void main(String[] args)throws InterruptedException{
        DelayQueue<DelayQueueValue<Order>> delayQueue = new DelayQueue<>();
        new provider(delayQueue).start();
        new consumer(delayQueue).start();
        for(int i=0;i<15;i++){
            Thread.sleep(500);
            System.out.println(i*500);
        }
    }
}

在這裏插入圖片描述
結果解析:我們向阻塞隊列中插入兩條數據,過期時間分別是5s和8s,消費者一直去take,則到期時間到了之後則會將數據從阻塞隊列中取出並進行業務操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章