Java并發編程之堵塞隊列介紹以及SkipList(跳表)

堵塞隊列

先了解一下生產者消費者模式:

生產者就是生產數據的一方,消費者就是消費數據的另一方。在多線程開發中,如果生產者處理速度很快,而消費者處理速度很慢,那么生產者就必須等待消費者處理完,才能繼續生產數據。如果消費者的處理能力大于生產者,那么消費者就必須等待生產者。為了解決這種生產消費能力不均衡的問題,便有了生產者和消費者模式。

生產者和消費者模式是通過一個容器來解決生產者和消費者的強耦合問題,即有了MQ(Message Queue)中間件。生產者和消費者彼此之間不直接通信,而是通過阻塞隊列來進行通信,所以生產者生產完數據之后不用等待消費者處理,直接推送給阻塞隊列,消費者直接從阻塞隊列里獲取數據。

基本概念:

1)、當隊列滿的時候,插入元素的線程被阻塞,直達隊列不滿。

2)、隊列為空的時候,獲取元素的線程被阻塞,直到隊列不空。

這種模式最常見的就是在MQ里面,即消息隊列(Message Queue)框架,這里就不多談了。

BlockQueue<T>

堵塞隊列都是基于這個接口實現的

基本接口定義,個人覺得如果用堵塞隊列的話就應該推薦使用堵塞方法,即put()以及take()

方法拋出異常帶有返回值堵塞超時退出
插入方法addofferputoffer(Time)
刪除方法removepolltakepoll(Time)
判斷是否存在elementpeekN/AN/A

1)、拋出異常:當隊列滿時,如果再往隊列里插入元素,會拋出IllegalStateException異常。當隊列空時,從隊列里獲取元素會拋出NoSuchElementException異常。

2)、返回特殊值:當往隊列插入元素時,會返回元素是否插入成功,成功返回true。如果是移除方法,則是從隊列里取出一個元素,如果沒有則返回null。

3)、一直阻塞:當阻塞隊列滿時,如果生產者線程往隊列里put元素,隊列會一直阻塞生產者線程,直到隊列可用或者響應中斷退出。當隊列空時,如果消費者線程從隊列里take元素,隊列會阻塞住消費者線程,直到隊列不為空。

4)、超時退出:當阻塞隊列滿時,如果生產者線程往隊列里插入元素,隊列會阻塞生產者線程一段時間,如果超過了指定的時間,生產者線程就會退出。

堵塞隊列分有界和無界隊列

有界:會有設定的隊列大小,不能無限制的創建隊列大小

無界:指理論上可以無限隊列的大小,但是實際情況,每個服務器都會有大小,只能說是理論上的,實際應用的時候會容易撐滿磁盤或內存,建議使用有界堵塞隊列

常用的堵塞隊列有一下幾種:

ArrayBlockingQueue:一個由數組組成的有界堵塞隊列,是一個FIFO隊列,不過要求創建對象的時候創建大小,內部是由ReentrantLock和Condition實現堵塞策略,單個鎖

    /** Main lock guarding all access */final ReentrantLock lock;/** Condition for waiting takes */private final Condition notEmpty;/** Condition for waiting puts */private final Condition notFull;

LinkedBlockingQueue:由鏈表結構組成的有界堵塞隊列,也是一個FIFO隊列,不要求創建對象是設置默認大小,不設置為Integer.MAX_VAUE;有兩個鎖,一個用于插入元素,另外一個用于獲取元素

    /** Lock held by take, poll, etc */private final ReentrantLock takeLock = new ReentrantLock();/** Wait queue for waiting takes */private final Condition notEmpty = takeLock.newCondition();/** Lock held by put, offer, etc */private final ReentrantLock putLock = new ReentrantLock();/** Wait queue for waiting puts */private final Condition notFull = putLock.newCondition();

PriorityBlockingQueue:一個支持優先級排序的無界阻塞隊列。默認情況下,按照自然順序,要么實現compareTo()方法,指定構造參數Comparator。

DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。支持延時獲取的元素的阻塞隊列,即可以延時推送,元素必須要實現Delayed接口。

SynchronousQueue:一個不存儲元素的阻塞隊列,所以在執行速度上會比其他堵塞隊列要快,每一個put操作都要等待一個take操作;

LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。可以從隊列的頭和尾都可以插入和移除元素,實現工作密取,方法名帶了First對頭部操作,帶了last從尾部操作。

跳表(SkipList)

是一種加快查詢鏈表速度的一種方法,以空間換時間的一種方法,代表的類有ConcurrentSkipListMap和ConcurrentSkipListSet,也是一種隨機概率數據結構;

在原有的鏈表結構(鏈表是按順序排序的)上加上一層鏈表結構,但這個是隨機指定的,類似于數據庫的索引,可加多層索引鏈表查詢的時間復雜度為O(logn),快跟上了紅黑樹的查詢速度,下面為圖解示例:

     ** Head nodes          Index nodes* +-+    right        +-+                      +-+* |2|---------------->| |--------------------->| |->null* +-+                 +-+                      +-+*  | down              |                        |*  v                   v                        v* +-+            +-+  +-+       +-+            +-+       +-+* |1|----------->| |->| |------>| |----------->| |------>| |->null* +-+            +-+  +-+       +-+            +-+       +-+*  v              |    |         |              |         |* Nodes  next     v    v         v              v         v* +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+* | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null* +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+*

寫時復制容器

通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,復制出一個新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器。這樣做的好處是我們可以對容器進行并發的讀,而不需要加鎖,因為當前容器不會添加任何元素。所以寫時復制容器也是一種讀寫分離的思想,讀和寫不同的容器。如果讀的時候有多個線程正在向容器添加數據,讀還是會讀到舊的數據,因為寫的時候不會鎖住舊的,只能保證最終一致性。

常見的有CopyOnWriteArrayList以及CopyOnWriteArraySet;

適用讀多寫少的并發場景,常見應用:白名單/黑名單, 商品類目的訪問和更新場景。

以下為圖解,在寫完后,原本的引用會重新指向新的數組對象,所以就會存在內存占用問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/537163.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537163.shtml
英文地址,請注明出處:http://en.pswp.cn/news/537163.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python生成list的時候 可以用lamda也可以不用_python 可迭代對象,迭代器和生成器,lambda表達式...

分頁查找#5.隨意寫一個20行以上的文件(divmod)# 運行程序&#xff0c;先將內容讀到內存中&#xff0c;用列表存儲。# l []# 提示&#xff1a;一共有多少頁# 接收用戶輸入頁碼&#xff0c;每頁5條&#xff0c;僅輸出當頁的內容def read_page(bk_list,n,endlineNone):startline …

數據挖掘技術簡介[轉]

關鍵詞&#xff1a; 關鍵詞&#xff1a;數據挖掘 數據集合 1. 引言  數據挖掘(Data Mining)是從大量的、不完全的、有噪聲的、模糊的、隨機的數據中提取隱含在其中的、人們事先不知道的、但又是潛在有用的信息和知識的過程。隨…

樹莓派安裝smbus_樹莓派使用smbus不兼容問題(no module named 'smbus')

樹莓派使用smbus不兼容問題(no module named ‘smbus’)python3.5–3.6可以使用smbus2代替smbus1. 先參考以下方法&#xff1a;github討論樹莓派社區2.Pypi上可以下載smbus2smbus2PyPi介紹&#xff1a;當前支持的功能有&#xff1a;獲取i2c功能(I2C_FUNCS)read_bytewrite_byter…

Java并發編程之線程池ThreadPoolExecutor解析

線程池存在的意義 平常使用線程即new Thread()然后調用start()方法去啟動這個線程&#xff0c;但是在頻繁的業務情況下如果在生產環境大量的創建Thread對象是則會浪費資源&#xff0c;不僅增加GC回收壓力&#xff0c;并且還浪費了時間&#xff0c;創建線程是需要花時間的&…

面向過程的門面模式

{*******************************************************}{ }{ 業務邏輯一 }{ }{ 版權所有 (C) 2008 陳…

Java并發編程之線程定時器ScheduledThreadPoolExecutor解析

定時器 就是需要周期性的執行任務&#xff0c;也叫調度任務&#xff0c;在JDK中有個類Timer是支持周期性執行&#xff0c;但是這個類不建議使用了。 ScheduledThreadPoolExecutor 繼承自ThreadPoolExecutor線程池&#xff0c;在Executors默認創建了兩種&#xff1a; newSin…

python xml轉換鍵值對_Python 提取dict轉換為xml/json/table并輸出

#!/usr/bin/python#-*- coding:gbk -*-#設置源文件輸出格式import sysimport getoptimport jsonimport createDictimport myConToXMLimport myConToTabledef getRsDataToDict():#獲取控制臺中輸入的參數&#xff0c;并根據參數找到源文件獲取源數據csDict{}try:#通過getopt獲取…

應用開發框架之——根據數據表中的存儲的方法名稱來調用方法

功用一&#xff1a;在框架里面根據存儲在數據表中的方法名來動態調用執行方法。 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 class(TForm) Button1: TButton; procedu…

Spring IOC容器組件注入的幾種方式

整理一下之前Spring的學習筆記&#xff0c;大致有一下幾種Spring注入到容器中的方法: 1&#xff09;、配置在xml的方式。 2&#xff09;、開啟包掃描ComponentScan使用Component&#xff0c;Service&#xff0c;Controller&#xff0c;Repository&#xff08;其實后三個都繼承…

我們是如何拿下Google和Facebook Offer的?

http://posts.careerengine.us/p/57c3a1c1a09633ee7e57803c 大家好&#xff0c;我是小高&#xff0c;CMU CS Master&#xff0c;來Offer第一期學員&#xff0c;2014年初在孫老師的帶領下我在幾個月的時間內進入了Yahoo&#xff0c;并工作了近2年。2016年初&#xff0c;Yahoo工作…

Spring中BeanFactory和FactoryBean的區別

先介紹一下Spring的IOC容器到底是個什么東西&#xff0c;都說是一個控制反轉的容器&#xff0c;將對象的控制權交給IOC容器&#xff0c;其實在看了源代碼之后&#xff0c;就會發現IOC容器只是一個存儲單例的一個ConcurrentHashMap<String, BeanDefinition> BeanDefiniti…

python中數字和字符串可以直接相加_用c語言或者python將文件中特定字符串后面的數字相加...

匿名用戶1級2014-08-31 回答代碼應該不難吧。既然用爬蟲爬下來了&#xff0c;為什么爬取數據的時候沒做處理呢。之前用過Scrapy爬蟲框架&#xff0c;挺好用的&#xff0c;你可研究下。代碼&#xff1a;#!codingutf-8import osimport reimport random# 獲取當前目錄文件列表def …

Spring中Aware的用法以及實現

Aware 在Spring當中有一些內置的對象是未開放給我們使用的&#xff0c;例如Spring的上下文ApplicationContext、環境屬性Environment&#xff0c;BeanFactory等等其他的一些內置對象&#xff0c;而在我們可以通過實現對應的Aware接口去拿到我們想要的一些屬性&#xff0c;一般…

c#字符型轉化為asc_C#字符串和ASCII碼的轉換

//字符轉ASCII碼&#xff1a;public static int Asc(string character){if (character.Length 1){System.Text.ASCIIEncoding asciiEncoding new System.Text.ASCIIEncoding();int intAsciiCode (int)asciiEncoding.GetBytes(character)[0];return (intAsciiCode);}else{thr…

topcoder srm 625 div1

problem1 link 假設第$i$種出現的次數為$n_{i}$&#xff0c;總個數為$m$&#xff0c;那么排列數為$T\frac{m!}{\prod_{i1}^{26}(n_{i}!)}$ 然后計算回文的個數&#xff0c;只需要考慮前一半&#xff0c;得到個數為$R$&#xff0c;那么答案為$\frac{R}{T}$. 為了防止數字太大導致…

Spring的組件賦值以及環境屬性@PropertySource

PropertySource 將指定類路徑下的.properties一些配置加載到Spring當中&#xff0c; 有個跟這個差不多的注解PropertySources Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented public interface PropertySources {PropertySource[] value();} 使用…

python語音識別框架_橫評:五款免費開源的語音識別工具

編者按&#xff1a;本文原作者 Cindi Thompson&#xff0c;美國德克薩斯大學奧斯汀分校(University of Texas at Austin)計算機科學博士&#xff0c;數據科學咨詢公司硅谷數據科學(Silicon Valley Data Science&#xff0c;SVDS)首席科學家&#xff0c;在機器學習、自然語言處理…

csharp read excel file get sheetName list

1 /// <summary>2 /// 3 /// 塗聚文4 /// 201208035 /// Geovin Du6 ///找到EXCEL的工作表名稱 要考慮打開的文件的進程問題7 /// </summary>8 /// <param name"filename">…

Spring Bean的生命周期以及IOC源碼解析

IOC源碼這一塊太多只能講個大概吧&#xff0c;建議還是去買本Spring IOC源碼解析的書來看比較好&#xff0c;我也是自己看源代碼以及視頻整理的筆記 Bean的生命周期大概可以分為四個階段&#xff0c;具體的等會再說&#xff0c;先看看IOC的源碼吧 1、bean的創建 2、bean的屬…