首先我們通常說的并發包就是java.util.concurrent包及其子包。集中了Java并發的各種基礎工具類。
一、這個并發包在哪
上面的包就是傳說中的并發包。
為什么這個并發包就比較流弊呢?
原因主要有以下幾點。
提供了幾個比synchronized更加高級的各種同步結構。例如:CountDownLatch、CyclicBarrier、Semaphore等。可以實現更加豐富的多線程的操作。比如利用Semaphore作為資源控制器(其實可以簡單理解為信號量),限制同時工作的線程的數量。
各種線程安全的容器。例如:無序的ConcurrentHashMap、有序的ConcurrentSkipListMap和線程安全的動態數組CopyOnWriteArrayList等。
各種并發隊列的實現。比較典型的有ArrayBlockingQueue、SynchorousQueue或者優先級隊列PriorityBlockingQueue等。
強大的Executor框架,可以創建各種不同類型的線程池,調度任務的運行,絕大部分情況下,用戶不需要自己從頭實現線程池和調度任務。
二、講幾個比較流弊用的較多的
萬變不離其宗,拋磚引玉,如果這幾個基礎的你了解的比較好,以后再深入拓展就比較簡單了。
空談誤國,實干興邦,謝謝看嘛。
1、Semaphore
簡單說,他就是一個計數器,其基本邏輯基于acquire/release申請或者獲得資源。
package com.newframe.controllers.api;import lombok.Data;
import org.apache.commons.lang3.StringUtils;import java.util.concurrent.Semaphore;/*** 第一步* 創建一個實現了Runnable接口的信號量工作類* 并重寫它的run方法,讓他做我想要做的事情*/public class SemaphoreWorker implements Runnable{private String name;private Semaphore semaphore;public String getName() {return name;}public void setName(String name) {this.name = name;}//創建一個構造函數public SemaphoreWorker(Semaphore semaphore) {this.semaphore = semaphore;}@Overridepublic void run() {try {log("準備申請一個資源");semaphore.acquire();//申請資源log("申請到了資源");log("執行");} catch (InterruptedException e) {e.printStackTrace();}finally {//釋放資源semaphore.release();log("釋放資源成功");}}private void log(String msg){if (StringUtils.isEmpty(msg)){name = Thread.currentThread().getName();}System.out.println(name + " " + msg);}
}
package com.newframe.controllers.api;import java.util.concurrent.Semaphore;/*** 第二步* 創建一個Semaphore的測試類*/
public class TestSemaphore {public static void main(String[] args) {System.out.println("我要開始執行了");//創建一個Semaphore對象,允許3個資源Semaphore semaphore = new Semaphore(3);for (int i = 0; i < 10; i++) {SemaphoreWorker worker = new SemaphoreWorker(semaphore);//給線程一個名字worker.setName("線程"+i);Thread thread = new Thread(worker);thread.start();}}
}
在上面可以很清晰的看到Semaphore對資源信號量的控制。
如我上面的信號量給的3,就是最多只能有3個線程能同時申請到資源。其余線程需要等待申請到的線程釋放資源后才能獲得資源。
看輸出結果:
2、CountDownLatch和CyclicBarrier
他們的行為有一定的相似度。經常會用來要你理解他們有什么區別。
- CountDownLatch 控制的這個數量是不可以重置的,兩個線程不能夠同時搶占CountDownLatch控制的資源數量。在前面的線程執行完后,后面的線程才可以執行。
- CycliBarrier這個就很有意思了。這個比如說你有5個士力架,你上學,你吃完了,你一定要把5個都吃完,你立馬可以獲得新的5個士力架。你怕不怕。
3、CountDownLatch
下面我們來舉個例子
package com.newframe.controllers.api;import java.util.concurrent.CountDownLatch;/*** 創建第一個吃巧克力的家伙,叫他小明吧* 實現Runnable接口,并重寫其方法*/
public class FirstBatchWorker implements Runnable{private CountDownLatch latch;public FirstBatchWorker(CountDownLatch latch) {this.latch = latch;}@Overridepublic void run() {//執行countDown()操作latch.countDown();System.out.println("小明吃了一塊巧克力");}
}
package com.newframe.controllers.api;import java.util.concurrent.CountDownLatch;/*** 創建第二個吃巧克力的家伙,叫他小李吧* 實現Runnable接口,并重寫其方法*/
public class SecondBatchWorker implements Runnable{private CountDownLatch latch;public SecondBatchWorker(CountDownLatch latch) {this.latch = latch;}@Overridepublic void run() {try {latch.await();System.out.println("小李吃了一塊巧克力");} catch (InterruptedException e) {e.printStackTrace();}}
}
package com.newframe.controllers.api;import java.util.concurrent.CountDownLatch;/*** 來測試一下LatchSample*/
public class TestCountDownLatch {public static void main(String[] args) {//一共5個巧克力//同時有5個線程可以獲取到資源CountDownLatch latch = new CountDownLatch(5);//下面的線程是按照順序執行的。//五個小明線程for (int i = 0; i < 10; i++) {Thread thread = new Thread(new FirstBatchWorker(latch));thread.start();}//這個線程一定要等到上個線程全部執行完成了才可以執行for (int i = 0; i < 5; i++) {Thread thread = new Thread(new SecondBatchWorker(latch));thread.start();}}
}
執行結果
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小明吃了一塊巧克力
小李吃了一塊巧克力
小李吃了一塊巧克力
小李吃了一塊巧克力
小李吃了一塊巧克力
小李吃了一塊巧克力
CountDownLatch用于線程間等待操作結束是非常普遍簡單的用法。
4、CyclicBarrier
如果說CountDownLatch 是用于線程間等待操作結束的協調,那么CyclicBarrier其實反映的是線程間并行運行時的協調。
下面來看一個例子。
package com.newframe.controllers.api;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*** 創建一個CyclicBarrier類,實現Runable接口*/
public class CyclicBarrierWorker implements Runnable{private CyclicBarrier cyclicBarrier;public CyclicBarrierWorker(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {try {for (int i = 0; i < 3; i++) {System.out.println("執行");cyclicBarrier.await();}} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}
}
package com.newframe.controllers.api;import java.util.concurrent.CyclicBarrier;/*** 測試一下CyclicBarrier*/
public class TestCyclicBarrier {public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {@Overridepublic void run() {System.out.println("操作再次......執行");}});for (int i = 0; i < 5; i++) {Thread thread = new Thread(new CyclicBarrierWorker(barrier));thread.start();}}
}
執行
執行
執行
執行
執行
操作再次......執行
執行
執行
執行
執行
執行
操作再次......執行
執行
執行
執行
執行
執行
操作再次......執行
三、Java并發庫的小知識
Java并發庫還提供了Phaser,功能與CountDownLatch很接近。
Java并發庫還提供了線程安全的Map、List和Set等容器。
ConcurrentHashMap:側重通過鍵值對,放入或者獲取的速度,對順序無所謂。
ConcurrentSkipListMap:通過鍵值對操作數據,側重數據的順序操作。如果對大量數據進行頻繁的修改,ConcurrentSkipListMap也是有優勢的。
好啦,今天就到這里啦。好記性比不上爛筆頭,還是的親自實踐一下的。
總結
以上是生活随笔為你收集整理的Java并发包中那些值得学习的并发工具类(空谈误国,实干兴邦,代码示范,抛砖引玉)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。