概述
為了提高接口的響應(yīng)速度,可以使用ThreadPoolExecutor + Runnable 或者ThreadPoolExecutor 并發(fā)調(diào)用 技術(shù)來(lái)并行執(zhí)行task沿腰。但是ThreadPoolExecutor有個(gè)特點(diǎn),就是當(dāng)core線程不足以應(yīng)付請(qǐng)求的時(shí)候训桶,會(huì)將task加入到隊(duì)列中杜耙。一旦使用隊(duì)列,那么就可能出現(xiàn)隊(duì)列爆掉或者隊(duì)列導(dǎo)致的內(nèi)存溢出問(wèn)題裁僧。為了盡快提供接口響應(yīng)速度,但是又不想使用隊(duì)列特性的話÷辈模可以使用信號(hào)量來(lái)做到。
Semaphore信號(hào)量管理著一組許可,在執(zhí)行操作時(shí)需要首先獲得許可,并在使用后釋放許可峦失。如果已經(jīng)沒(méi)有許可了, acquire方法將一直阻塞,直到有許可扇丛。Semaphore可以用來(lái)實(shí)現(xiàn)有界阻塞容器。
信號(hào)量簡(jiǎn)單例子
這里使用JAVA并發(fā)編程一書(shū)中的例子來(lái)說(shuō)明信號(hào)量的基本用法尉辑。
public class BoundedHashSet<T> {
public static void main(String[] args) throws Exception {
BoundedHashSet<String> set = new BoundedHashSet<>(2);
set.add("1");
set.add("2");
set.remove("2");
set.add("3");
System.out.println(JSON.toJSONString(set));
}
private final Set<T> tempSet;
private final Semaphore sem;
public BoundedHashSet(int size) {
this.tempSet = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(size);
}
public boolean add(T o) throws Exception {
sem.acquire();
boolean isAdd = false;
try{
isAdd = tempSet.add(o);
return isAdd;
}
finally {
if (!isAdd) {
sem.release();
}
}
}
public boolean remove(Object o) {
boolean isRemoved = tempSet.remove(o);
if (isRemoved) {
sem.release();
}
return isRemoved;
}
}
這里例子實(shí)現(xiàn)了有界阻塞的HashSet帆精。只允許這個(gè)HashSet存放兩個(gè)元素,如果想存第三個(gè)元素隧魄,必須等到有人把HashSet中的元素remove掉卓练。每次add之前先申請(qǐng)一個(gè)許可,如果能申請(qǐng)到购啄,則正常添加元素襟企。申請(qǐng)不到,則acquire()方法會(huì)一直阻塞狮含。remove操作里面顽悼,則有一個(gè)釋放許可的操作。
ThreadPoolExecutor中使用信號(hào)量
在ThreadPoolExecutor中几迄,我們?cè)诙xcore線程參數(shù)的時(shí)候蔚龙,比如定義為10個(gè),那么使用信號(hào)量的時(shí)候映胁,初始化參數(shù)也設(shè)置為10.
Semaphore<Integer> sem= new Semaphore<>(10);
ThreadPoolExecutor中,如果不想用到隊(duì)列木羹,就必須保證線程池中始終只有core線程在工作。那么當(dāng)請(qǐng)求太多屿愚,core線程處理不過(guò)來(lái)的時(shí)候汇跨,用信號(hào)量進(jìn)行阻塞务荆,保證只有當(dāng)core線程的某些線程執(zhí)行完后,阻塞才解開(kāi)穷遂。