性能測試作到後面,一些特殊的場景利用經常使用的現成工具知足不了需求,因此你須要學習java寫一些特定協議的壓測腳本,那你不得不研究多線程或線程池,而此時你也必定會遇到java併發編程中的幾個類,今天重點講解這3個類,CountDownLanch、CyclicBarrier、Semaphore,但願你們之後看到的時候知道是幹嗎用的。java
接下來,我就最近學習的成果,下面和你們舉例子講解一下,幫助理解。web
1CountDownLanch數據庫
場景編程
工做中每每會遇到須要異步處理的任務,此時咱們就會利用多線程的方式去處理,即啓動子線程去執行任務,而此時主線程阻塞,等待全部的子線程完成任務後,再去作一些彙總統計工做。多線程
CountDownLanch 是一個倒數計數器, 給一個初始值(>=0), 而後每一次調用countDown就會減1, 這很符合等待多個子線程結束的場景: 一個線程結束的時候, countDown一次, 直到全部的線程都countDown了 , 那麼全部子線程就都結束了。併發
先看看CountDownLanch提供的方法。app
await: 會阻塞等待計數器減小到0位置. 帶參數的await是多了等待時間。異步
countDown: 將當前的計數減1。ide
getCount(): 返回當前的計數。函數
顯而易見, 咱們只須要在子線程執行以前, 賦予初始化countDownLanch, 並賦予線程數量爲初始值。
每一個線程執行完畢的時候, 就countDown一下。主線程只須要調用await方法, 能夠等待全部子線程執行結束。
例子
package ht.test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CountDownLatchTest {
// 參數是2表示對象執行2次countDown方法才能釋放鎖
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
// 定義線程數
int subThreadNum = 5;
// 取得一個倒計時器,從5開始
CountDownLatch countDownLatch = new CountDownLatch(subThreadNum);
// 依次建立5個線程,並啓動
for (int i = 0; i < subThreadNum; i++) {
SubThread runnablethread = new SubThread(5000, countDownLatch);
new Thread(runnablethread).start();
}
// 主線程工做,此處能夠添加一些額外的工做
// mainWork();
// 等待全部的子線程結束
countDownLatch.await();
System.out.println("all all all Main Thread work done!");
}
static class SubThread implements Runnable {
private CountDownLatch countDownLatch;
private long workTime;
public SubThread(long workTime, CountDownLatch countDownLatch) {
this.workTime = workTime;
this.countDownLatch = countDownLatch;
}
public void run() {
// TODO Auto-generated method stub
try {
System.out.println("線程Id:" + Thread.currentThread().getId() + " Sub thread is starting!");
Thread.sleep(workTime);
System.out.println("線程Id:" + Thread.currentThread().getId() + " Sub thread is stopping!");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 線程結束時,將計時器減一
countDownLatch.countDown();
}
}
}
}
2CyclicBarrier
場景
咱們在作壓測的時候,如要真正的併發,那麼在建立線程成功後須要等待其餘線程也建立好了,一塊兒等着,同時發送請求,此時就用到了CyclicBarrier。
CyclicBarrier的字面意思是可循環使用(Cyclic)的屏障(Barrier)。它要作的事情是,讓一組線程到達一個屏障(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續運行。
例子
package ht.test;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
// 初始化線程等待的個數,當調用await()函數的次數和這裏的數值一致時候,接下去執行。
static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 子線程
c.await();
} catch (Exception e) {
}
System.out.println(1);
}
}).start();
try {
// 主線程,若此處註冊掉,執行結果爲2,而且子線程一直阻塞着
c.await();
} catch (Exception e) {
}
System.out.println(2);
}
}
3Semaphore
場景
有時候併發太大的時候,咱們須要人工的控制,譬如一些數據庫的鏈接數這樣子的,資源畢竟有限的,不可能無限去建立鏈接,此時咱們就須要利用Semaphore去控制。
Semaphore(信號量)是用來控制同時訪問特定資源的線程數量,它經過協調各個線程,以保證合理的使用公共資源。能夠控制系統的流量,拿到信號量的線程能夠進入,不然就等待。經過acquire()和release()獲取和釋放訪問許可。
例子
package ht.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class TestSemaphore {
public static void main(String[] args) {
// 線程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5個線程同時訪問
final Semaphore semp = new Semaphore(5);
// 模擬20個客戶端訪問
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
@Override
public void run() {
try {
// 獲取許可
semp.acquire();
System.out.println("Accessing: " + NO);
// 模擬實際業務邏輯
Thread.sleep((long) 10000);
// 訪問完後,釋放
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(semp.getQueueLength());
// 退出線程池
exec.shutdown();
}
}
不知道,你有沒有理解,在此也只是拋磚引玉一下,你們在實踐中能夠繼續學習研究。
更多其餘測試內容能夠參考連接文末更多測試好文章