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)了解更多。