JDK5新特性之線(xiàn)程同步工具類(lèi)(三)
來(lái)源:程序員人生 發(fā)布時(shí)間:2014-11-22 08:46:08 閱讀次數(shù):3316次
1. Semaphore
Semaphore可以控制同時(shí)訪(fǎng)問(wèn)資源的線(xiàn)程個(gè)數(shù), 例如: 實(shí)現(xiàn)1個(gè)文件允許的并發(fā)訪(fǎng)問(wèn)數(shù).
Semaphore實(shí)現(xiàn)的功能就類(lèi)似廁所有5個(gè)坑, 加入有10個(gè)人要上廁所, 那末同時(shí)只能有5個(gè)人能夠占用, 當(dāng)5個(gè)人中的任何1個(gè)人離開(kāi)后, 其中在等待的另外5個(gè)人中就有1個(gè)可以占用了. 另外等待的5個(gè)人中可以是隨機(jī)取得優(yōu)先機(jī)會(huì),
也能夠使依照先來(lái)后到的順序取得機(jī)會(huì), 這取決于構(gòu)造Semaphore對(duì)象時(shí)傳入的參數(shù)選項(xiàng).
public class SemaphoreTest {
public static void main(String[] args) {
// 創(chuàng)建1個(gè)線(xiàn)程池
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3); // 表示當(dāng)前有3盞燈(允許3個(gè)并發(fā))
// 啟動(dòng)5個(gè)線(xiàn)程
for (int i = 0; i < 5; i++) {
service.execute(new Runnable() {
public void run() {
try {
sp.acquire(); // 點(diǎn)亮1盞燈
// availablePermits: 表示可使用的燈
System.out.println("線(xiàn)程" + Thread.currentThread().getName()
+ " 進(jìn)入,當(dāng)前已有" + (3 - sp.availablePermits()) + "個(gè)并發(fā)");
Thread.sleep((long) (Math.random() * 10000));
System.out.println("線(xiàn)程" + Thread.currentThread().getName() + " 行將離開(kāi)");
sp.release(); // 熄滅1盞燈(釋放)
System.out.println("線(xiàn)程" + Thread.currentThread().getName()
+ " 已離開(kāi),當(dāng)前已有" + (3 - sp.availablePermits()) + "個(gè)并發(fā)");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
單個(gè)Semaphore對(duì)象可以實(shí)現(xiàn)互斥鎖的功能, 并且可以是由1個(gè)線(xiàn)程取得了"鎖", 再由另外一個(gè)線(xiàn)程釋放"鎖", 這可利用于死鎖恢復(fù)的1些場(chǎng)合.
線(xiàn)程pool⑴-thread⑴ 進(jìn)入,當(dāng)前已有1個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑵ 進(jìn)入,當(dāng)前已有2個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑷ 進(jìn)入,當(dāng)前已有3個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑷ 行將離開(kāi)
線(xiàn)程pool⑴-thread⑷ 已離開(kāi),當(dāng)前已有2個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑶ 進(jìn)入,當(dāng)前已有3個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑵ 行將離開(kāi)
線(xiàn)程pool⑴-thread⑵ 已離開(kāi),當(dāng)前已有2個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑸ 進(jìn)入,當(dāng)前已有3個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑸ 行將離開(kāi)
線(xiàn)程pool⑴-thread⑸ 已離開(kāi),當(dāng)前已有2個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑴ 行將離開(kāi)
線(xiàn)程pool⑴-thread⑴ 已離開(kāi),當(dāng)前已有1個(gè)并發(fā)
線(xiàn)程pool⑴-thread⑶ 行將離開(kāi)
線(xiàn)程pool⑴-thread⑶ 已離開(kāi),當(dāng)前已有0個(gè)并發(fā)
2. CyclicBarrier
表示大家彼此等待,集合好后才開(kāi)始動(dòng)身,分散活動(dòng)后又在指定地點(diǎn)集合碰面。
這就好比全部公司的人員里利用周末時(shí)間集體遠(yuǎn)足1樣,先各自從家動(dòng)身到公司集合后,再同時(shí)動(dòng)身到公園游玩,在指定地點(diǎn)集合后再同時(shí)開(kāi)始就餐。
public class CyclicBarrierTest {
public static void main(String[] args) {
// 開(kāi)啟1個(gè)線(xiàn)程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 參數(shù)3: 表示有3個(gè)到齊了才可以往下走,否則1直處于等待狀態(tài)
final CyclicBarrier cb = new CyclicBarrier(3);
// 創(chuàng)建3個(gè)線(xiàn)程
for(int i = 0; i < 3; i++){
executorService.execute(new Runnable(){
@Override
public void run(){
try {
Thread.sleep((long)(Math.random() * 1000)); // 每一個(gè)線(xiàn)程“休息”的時(shí)間不同
System.out.println("線(xiàn)程" + Thread.currentThread().getName()
+ "行將到達(dá)集合地點(diǎn)1,當(dāng)前已有" + (cb.getNumberWaiting() + 1)
+ "個(gè)已到達(dá)," + (cb.getNumberWaiting() == 2 ? "都到齊了,繼續(xù)前進(jìn)" : "正在等候"));
cb.await(); // 先到的等待后到的,當(dāng)3個(gè)都到達(dá)時(shí)才會(huì)繼續(xù)向下履行
Thread.sleep((long)(Math.random() * 1000)); // 每一個(gè)線(xiàn)程“休息”的時(shí)間不同
System.out.println("線(xiàn)程" + Thread.currentThread().getName()
+ "行將到達(dá)集合地點(diǎn)2,當(dāng)前已有" + (cb.getNumberWaiting() + 1)
+ "個(gè)已到達(dá)," + (cb.getNumberWaiting() == 2 ? "都到齊了,繼續(xù)前進(jìn)" : "正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*1000)); // 每一個(gè)線(xiàn)程“休息”的時(shí)間不同
System.out.println("線(xiàn)程" + Thread.currentThread().getName()
+ "行將到達(dá)集合地點(diǎn)3,當(dāng)前已有" + (cb.getNumberWaiting() + 1)
+ "個(gè)已到達(dá),"+ (cb.getNumberWaiting() == 2 ? "都到齊了,繼續(xù)前進(jìn)" : "正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
executorService.shutdown();
}
}
3個(gè)線(xiàn)程干完各自的任務(wù),在不同的時(shí)刻到達(dá)集合地點(diǎn)后,就能夠接著忙各自的工作去了,再到達(dá)新的集合點(diǎn),再去忙各自的工作。
線(xiàn)程pool⑴-thread⑵行將到達(dá)集合地點(diǎn)1,當(dāng)前已有1個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑶行將到達(dá)集合地點(diǎn)1,當(dāng)前已有2個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑴行將到達(dá)集合地點(diǎn)1,當(dāng)前已有3個(gè)已到達(dá),都到齊了,繼續(xù)前進(jìn)
線(xiàn)程pool⑴-thread⑵行將到達(dá)集合地點(diǎn)2,當(dāng)前已有1個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑶行將到達(dá)集合地點(diǎn)2,當(dāng)前已有2個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑴行將到達(dá)集合地點(diǎn)2,當(dāng)前已有3個(gè)已到達(dá),都到齊了,繼續(xù)前進(jìn)
線(xiàn)程pool⑴-thread⑶行將到達(dá)集合地點(diǎn)3,當(dāng)前已有1個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑵行將到達(dá)集合地點(diǎn)3,當(dāng)前已有2個(gè)已到達(dá),正在等候
線(xiàn)程pool⑴-thread⑴行將到達(dá)集合地點(diǎn)3,當(dāng)前已有3個(gè)已到達(dá),都到齊了,繼續(xù)前進(jìn)
3. CountDownLatch
猶如倒計(jì)時(shí)計(jì)數(shù)器, 調(diào)用CountDownLatch對(duì)象的countDown方法就將計(jì)數(shù)器減1, 當(dāng)計(jì)數(shù)到達(dá)0時(shí), 則所有等待者或單個(gè)等待者開(kāi)始履行.
利用: 裁判1聲口令, 運(yùn)動(dòng)員同時(shí)開(kāi)始奔跑, 當(dāng)所有運(yùn)動(dòng)員都跑到終點(diǎn)后裁判公布結(jié)果. 還可以實(shí)現(xiàn)1個(gè)計(jì)劃需要多個(gè)領(lǐng)導(dǎo)都簽字后才能繼續(xù)向下實(shí)行的情況.
public class CountDownLatchTest {
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newCachedThreadPool();
// 子計(jì)數(shù)器, count為1
final CountDownLatch subCounter = new CountDownLatch(1);
// 主計(jì)數(shù)器, count為3
final CountDownLatch mainCounter = new CountDownLatch(3);
for(int i = 0; i < 3; i++){
service.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"正準(zhǔn)備接受命令!");
subCounter.await(); // 子線(xiàn)程等待
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"已接受命令!");
Thread.sleep((long)Math.random() * 10000);
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"回應(yīng)命令處理結(jié)果!");
mainCounter.countDown(); // 將計(jì)數(shù)器身上的計(jì)數(shù)減1, 當(dāng)計(jì)數(shù)為0時(shí), 主線(xiàn)程將開(kāi)始履行
} catch (Exception e) {
e.printStackTrace();
}
}
} );
}
Thread.sleep((long)Math.random() * 1000);
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"行將發(fā)布命令!");
subCounter.countDown(); // 將計(jì)數(shù)器身上的計(jì)數(shù)減1, 當(dāng)計(jì)數(shù)為0時(shí), 子線(xiàn)程開(kāi)始履行
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"已發(fā)送命令,正在等待結(jié)果!");
mainCounter.await(); // 主線(xiàn)程等待
System.out.println("線(xiàn)程 "+ Thread.currentThread().getName()+"已收到所有響應(yīng)結(jié)果!");
service.shutdown();
}
}
線(xiàn)程 pool⑴-thread⑴正準(zhǔn)備接受命令!
線(xiàn)程 pool⑴-thread⑶正準(zhǔn)備接受命令!
線(xiàn)程 pool⑴-thread⑵正準(zhǔn)備接受命令!
線(xiàn)程 main行將發(fā)布命令!
線(xiàn)程 main已發(fā)送命令,正在等待結(jié)果!
線(xiàn)程 pool⑴-thread⑵已接受命令!
線(xiàn)程 pool⑴-thread⑶已接受命令!
線(xiàn)程 pool⑴-thread⑴已接受命令!
線(xiàn)程 pool⑴-thread⑶回應(yīng)命令處理結(jié)果!
線(xiàn)程 pool⑴-thread⑵回應(yīng)命令處理結(jié)果!
線(xiàn)程 pool⑴-thread⑴回應(yīng)命令處理結(jié)果!
線(xiàn)程 main已收到所有響應(yīng)結(jié)果!
4. Exchanger
用于實(shí)現(xiàn)兩個(gè)人之間的數(shù)據(jù)交換, 每一個(gè)人在完成1定的事務(wù)后想與對(duì)方交換數(shù)據(jù), 第1個(gè)先拿出數(shù)據(jù)的人將1直等待第2個(gè)人拿著數(shù)據(jù)到來(lái)時(shí), 才能彼此交換數(shù)據(jù):
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
service.execute(new Runnable() {
@Override
public void run() {
try {
String data1 = "aaa";
System.out.println("線(xiàn)程 " + Thread.currentThread().getName() + " 正在把數(shù)據(jù): " + data1 + " 換出去!");
Thread.sleep((long) Math.random() * 10000);
String data2 = (String) exchanger.exchange(data1);
System.out.println("線(xiàn)程 " + Thread.currentThread().getName() + " 換回的數(shù)據(jù)為:" + data2);
} catch (Exception e) {
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
try {
String data1 = "bbb";
System.out.println("線(xiàn)程 " + Thread.currentThread().getName() + " 正在把數(shù)據(jù): " + data1 + " 換出去!");
Thread.sleep((long) Math.random() * 10000);
String data2 = (String) exchanger.exchange(data1);
System.out.println("線(xiàn)程 " + Thread.currentThread().getName() + " 換回的數(shù)據(jù)為:" + data2);
} catch (Exception e) {
}
}
});
}
}
線(xiàn)程 pool⑴-thread⑴ 正在把數(shù)據(jù): aaa 換出去!
線(xiàn)程 pool⑴-thread⑵ 正在把數(shù)據(jù): bbb 換出去!
線(xiàn)程 pool⑴-thread⑴ 換回的數(shù)據(jù)為:bbb
線(xiàn)程 pool⑴-thread⑵ 換回的數(shù)據(jù)為:aaa
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)