java.util.concurrent和工具類

三、Semaphor信號(hào)量

信號(hào)量可以干什么呢?根據(jù)一些閥值做訪問控制。我們這里模擬一個(gè)當(dāng)多個(gè)線程并發(fā)一段代碼的時(shí)候,如何控制其訪問速度

import java.util.Random; ?

import java.util.concurrent.Semaphore; ?

 

 

??public class SemaphoreTest { ?

??????private final static Semaphore MAX_SEMA_PHORE = new Semaphore(10); ?

??????public static void main(String []args) { ?

???????????for(int i = 0 ; i < 100 ; i++) { ?

????????????????final int num = i; ?

????????????????final Random radom = new Random(); ?

????????????????new Thread() { ?

?????????????????????public void run() { ?

?????????????????????????boolean acquired = false; ?

?????????????????????????try { ?

??????????????????????????????MAX_SEMA_PHORE.acquire(); ?

??????????????????????????????acquired = true; ?

??????????????????????????????System.out.println("我是線程:" + num + " 我獲得了使用權(quán)!" + DateTimeUtil.getDateTime()); ?

??????????????????????????????long time = 1000 * Math.max(1, Math.abs(radom.nextInt() % 10)); ?

??????????????????????????????Thread.sleep(time); ?

??????????????????????????????System.out.println("我是線程:" + num + " 我執(zhí)行完了!" + DateTimeUtil.getDateTime()); ?

?????????????????????????}catch(Exception e) { ?

??????????????????????????????e.printStackTrace(); ?

?????????????????????????}finally { ?

??????????????????????????????if(acquired) { ?

?????????????????????????????????MAX_SEMA_PHORE.release(); ?

??????????????????????????????} ?

?????????????????????????} ?

??????????????????????} ?

????????????????}.start(); ?

???????????} ?

??????} ?

??}

 

上述是簡(jiǎn)單模擬并發(fā)100個(gè)線程去訪問一段程序,此時(shí)要控制最多同時(shí)運(yùn)行的是10個(gè),用到了這個(gè)信號(hào)量,運(yùn)行程序用了一個(gè)線程睡眠一個(gè)隨機(jī)的時(shí)間來代替,你可以看到后面有線程說自己釋放了,就有線程獲得了,沒釋放是獲取不到的

 

四、Exchanger線程交互

用于線程之間交互數(shù)據(jù),且在并發(fā)時(shí)候使用,兩兩交換,交換中不會(huì)因?yàn)榫€程多而混亂,發(fā)送出去沒接收到會(huì)一直等,由交互器完成交互過程

 

import java.util.concurrent.Exchanger; ?

 

public class ExchangerTest { ?

 

????public static void main(String []args) { ?

????????final Exchanger <Integer>exchanger = new Exchanger<Integer>(); ?

????????for(int i = 0 ; i < 10 ; i++) { ?

????????????final Integer num = i; ?

????????????new Thread() { ?

????????????????public void run() { ?

????????????????????System.out.println("我是線程:Thread_" + this.getName() + "我的數(shù)據(jù)是:" + num); ?

????????????????????try { ?

????????????????????????Integer exchangeNum = exchanger.exchange(num); ?

????????????????????????Thread.sleep(1000); ?

????????????????????????System.out.println("我是線程:Thread_" + this.getName() + "我原先的數(shù)據(jù)為:" + num + " , 交換后的數(shù)據(jù)為:" + exchangeNum); ?

????????????????????} catch (InterruptedException e) { ?

????????????????????????e.printStackTrace(); ?

????????????????????} ?

????????????????} ?

????????????}.start(); ?

????????} ?

????} ?

} ?

這里運(yùn)行你可以看到,如果某個(gè)線程和另一個(gè)線程傳送了數(shù)據(jù),它接受到的數(shù)據(jù)必然是另一個(gè)線程傳遞給他的,中間步驟由Exchanger去控制

 

五、CyclicBarrier關(guān)卡模式

當(dāng)你在很多環(huán)節(jié)需要卡住,要多個(gè)線程同時(shí)在這里都達(dá)到后,再向下走,很有用

假如,團(tuán)隊(duì)出去旅行,大家一起先達(dá)到酒店住宿,然后一起達(dá)到游樂的地方游玩,然后一起坐車回家,每次需要點(diǎn)名后確認(rèn)相關(guān)人員均達(dá)到,然后LZ一聲令下,觸發(fā),大伙就瘋子般的出發(fā)了

import java.util.concurrent.BrokenBarrierException; ?

import java.util.concurrent.CyclicBarrier; ?

 

public class BarrierTest { ?

 

????private static final int THREAD_COUNT = 10; ?

 

????private final static CyclicBarrier CYCLIC_BARRIER = new CyclicBarrier(THREAD_COUNT ?, ?

????????new Runnable() { ?

????????????public void run() { ?

????????????????System.out.println("======>我是導(dǎo)游,本次點(diǎn)名結(jié)束,準(zhǔn)備走下一個(gè)環(huán)節(jié)!"); ?

????????????} ?

????????} ?

????); ?

 

????public static void main(String []args) ??

????????????throws InterruptedException, BrokenBarrierException { ?

????????for(int i = 0 ; i < 10 ; i++) { ?

????????????new Thread(String.valueOf(i)) { ?

????????????????public void run() { ?

????????????????????try { ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我們達(dá)到旅游地點(diǎn)!"); ?

????????????????????????CYCLIC_BARRIER.await(); ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我開始騎車!"); ?

????????????????????????CYCLIC_BARRIER.await(); ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我們開始爬山!"); ?

????????????????????????CYCLIC_BARRIER.await(); ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我們回賓館休息!"); ?

????????????????????????CYCLIC_BARRIER.await(); ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我們開始乘車回家!"); ?

????????????????????????CYCLIC_BARRIER.await(); ?

????????????????????????System.out.println("我是線程:" + this.getName() + " 我們到家了!"); ?

????????????????????} catch (InterruptedException e) { ?

????????????????????????e.printStackTrace(); ?

????????????????????} catch (BrokenBarrierException e) { ?

????????????????????????e.printStackTrace(); ?

????????????????????} ?

????????????????} ?

????????????}.start(); ?

????????} ?

????} ?

}

測(cè)試結(jié)果中可以發(fā)現(xiàn),大家一起走到某個(gè)步驟后,導(dǎo)游說:“我是導(dǎo)游,本次點(diǎn)名結(jié)束,準(zhǔn)備走下一個(gè)環(huán)節(jié)!”,然后才會(huì)進(jìn)入下一個(gè)步驟,OK,這個(gè)有點(diǎn)意思吧,其實(shí)賽馬也是這個(gè)道理,只是賽馬通常只有一個(gè)步驟,所以我們還有一個(gè)方式是:

 

六、CountDownLatch計(jì)數(shù)器

CountDownLatch的方式來完成賽馬操作,CountDownLatch是用計(jì)數(shù)器來做的,所以它不可以被復(fù)用,如果要多次使用,就要從新new一個(gè)出來才可以。我們下面的代碼中,用兩組賽馬,每組5個(gè)參與者來,做一個(gè)簡(jiǎn)單測(cè)試

import java.util.concurrent.CountDownLatch; ?

 

public class CountDownLatchTest { ?

 

????private final static int GROUP_SIZE = 5; ?

 

????public static void main(String []args) { ?

????????processOneGroup("分組1"); ?

????????processOneGroup("分組2"); ?

????} ?

 

????private static void processOneGroup(final String groupName) { ?

????????final CountDownLatch start_count_down = new CountDownLatch(1); ?

????????final CountDownLatch end_count_down = new CountDownLatch(GROUP_SIZE); ?

????????System.out.println("==========================>\n分組:" + groupName + "比賽開始:"); ?

????????for(int i = 0 ; i < GROUP_SIZE ; i++) { ?

????????????new Thread(String.valueOf(i)) { ?

????????????????public void run() { ?

????????????????????System.out.println("我是線程組:【" + groupName + "】,第:" + this.getName() + " 號(hào)線程,我已經(jīng)準(zhǔn)備就緒!"); ?

????????????????????try { ?

????????????????????????start_count_down.await();//等待開始指令發(fā)出即:start_count_down.countDown(); ?

????????????????????} catch (InterruptedException e) { ?

????????????????????????e.printStackTrace(); ?

????????????????????} ?

????????????????????System.out.println("我是線程組:【" + groupName + "】,第:" + this.getName() + " 號(hào)線程,我已執(zhí)行完成!"); ?

????????????????????end_count_down.countDown(); ?

????????????????} ?

????????????}.start(); ?

????????} ?

????????try { ?

????????????Thread.sleep(1000); ?

????????} catch (InterruptedException e) { ?

????????????e.printStackTrace(); ?

????????} ?

????????System.out.println("各就各位,預(yù)備!"); ?

????????start_count_down.countDown();//開始賽跑 ?

????????try { ?

????????????end_count_down.await();//等待多個(gè)賽跑者逐個(gè)結(jié)束 ?

????????} catch (InterruptedException e) { ?

????????????e.printStackTrace(); ?

????????} ?

????????System.out.println("分組:" + groupName + "比賽結(jié)束!"); ?

????} ?

}

 

 

 

本教程由尚硅谷教育大數(shù)據(jù)研究院出品,如需轉(zhuǎn)載請(qǐng)注明來源,歡迎大家關(guān)注尚硅谷公眾號(hào)(atguigu)了解更多。