久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Java多線程21:多線程下的其他組件之CyclicBarrier、Callable,、Future和FutureTask

 liang1234_ 2020-07-12

CyclicBarrier

接著講多線程下的其他組件,,第一個(gè)要講的就是CyclicBarrier。CyclicBarrier從字面理解是指循環(huán)屏障,,它可以協(xié)同多個(gè)線程,讓多個(gè)線程在這個(gè)屏障前等待,,直到所有線程都達(dá)到了這個(gè)屏障時(shí),,再一起繼續(xù)執(zhí)行后面的動(dòng)作??匆幌翪yclicBarrier的使用實(shí)例:

復(fù)制代碼
public static class CyclicBarrierThread extends Thread
{
    private CyclicBarrier cb;
    private int sleepSecond;
        
    public CyclicBarrierThread(CyclicBarrier cb, int sleepSecond)
    {
        this.cb = cb;
        this.sleepSecond = sleepSecond;
    }
        
    public void run()
    {
        try
        {
            System.out.println(this.getName() + "運(yùn)行了");
            Thread.sleep(sleepSecond * 1000);
            System.out.println(this.getName() + "準(zhǔn)備等待了, 時(shí)間為" + System.currentTimeMillis());
            cb.await();
            System.out.println(this.getName() + "結(jié)束等待了, 時(shí)間為" + System.currentTimeMillis());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        } 
    }
}
    
public static void main(String[] args)
{
    Runnable runnable = new Runnable()
    {
        public void run()
        {
            System.out.println("CyclicBarrier的所有線程await()結(jié)束了,,我運(yùn)行了, 時(shí)間為" + System.currentTimeMillis());
        }
    };
    CyclicBarrier cb = new CyclicBarrier(3, runnable);
    CyclicBarrierThread cbt0 = new CyclicBarrierThread(cb, 3);
    CyclicBarrierThread cbt1 = new CyclicBarrierThread(cb, 6);
    CyclicBarrierThread cbt2 = new CyclicBarrierThread(cb, 9);
    cbt0.start();
    cbt1.start();
    cbt2.start();
}
復(fù)制代碼

看一下運(yùn)行結(jié)果:

復(fù)制代碼
Thread-0運(yùn)行了
Thread-2運(yùn)行了
Thread-1運(yùn)行了
Thread-0準(zhǔn)備等待了, 時(shí)間為1444650316313
Thread-1準(zhǔn)備等待了, 時(shí)間為1444650319313
Thread-2準(zhǔn)備等待了, 時(shí)間為1444650322313
CyclicBarrier的所有線程await()結(jié)束了,我運(yùn)行了, 時(shí)間為1444650322313
Thread-2結(jié)束等待了, 時(shí)間為1444650322313
Thread-0結(jié)束等待了, 時(shí)間為1444650322313
Thread-1結(jié)束等待了, 時(shí)間為1444650322313
復(fù)制代碼

從運(yùn)行結(jié)果看,,由于是同一個(gè)CyclicBarrier,,Thread-0先運(yùn)行到了await()的地方,等著,;Thread-2接著運(yùn)行到了await()的地方,,還等著;Thread-1最后運(yùn)行到了await()的地方,,所有的線程都運(yùn)行到了await()的地方,,所以三個(gè)線程以及指定的Runnable"同時(shí)"運(yùn)行后面的代碼,,可以看到,await()之后,,四個(gè)線程運(yùn)行的時(shí)間一模一樣,,都是1444650322313。

從使用來看,,可能有人覺得CyclicBarrier和CountDownLatch有點(diǎn)像,,都是多個(gè)線程等待相互完成之后,再執(zhí)行后面的代碼,。實(shí)際上,,CountDownLatch和CyclicBarrier都是用于多個(gè)線程間的協(xié)調(diào)的,它們二者的幾個(gè)差別是:

1,、CountDownLatch是在多個(gè)線程都進(jìn)行了latch.countDown()后才會(huì)觸發(fā)事件,,喚醒a(bǔ)wait()在latch上的線程,而執(zhí)行countDown()的線程,,執(zhí)行完countDown()后會(huì)繼續(xù)自己線程的工作,;CyclicBarrier是一個(gè)柵欄,用于同步所有調(diào)用await()方法的線程,,線程執(zhí)行了await()方法之后并不會(huì)執(zhí)行之后的代碼,,而只有當(dāng)執(zhí)行await()方法的線程數(shù)等于指定的parties之后,這些執(zhí)行了await()方法的線程才會(huì)同時(shí)運(yùn)行

2,、CountDownLatch不能循環(huán)使用,,計(jì)數(shù)器減為0就減為0了,不能被重置,;CyclicBarrier提供了reset()方法,,支持循環(huán)使用

3、CountDownLatch當(dāng)調(diào)用countDown()方法的線程數(shù)等于指定的數(shù)量之后,,可以喚起多條線程的任務(wù),;CyclicBarrier當(dāng)執(zhí)行await()方法的線程等于指定的數(shù)量之后,只能喚起一個(gè)BarrierAction

注意,,因?yàn)槭褂肅yclicBarrier的線程都會(huì)阻塞在await方法上,,所以在線程池中使用CyclicBarrier時(shí)要特別小心,如果線程池的線程過少,,那么就會(huì)發(fā)生死鎖了

 

Callable,、Future和FutureTask

Callable

Callable和Runnable差不多,兩者都是為那些其實(shí)例可能被另一個(gè)線程執(zhí)行的類而設(shè)計(jì)的,,最主要的差別在于Runnable不會(huì)返回線程運(yùn)算結(jié)果,,Callable可以(假如線程需要返回運(yùn)行結(jié)果)

Future

Future是一個(gè)接口表示異步計(jì)算的結(jié)果,它提供了檢查計(jì)算是否完成的方法,,以等待計(jì)算的完成,,并獲取計(jì)算的結(jié)果,。Future提供了get()、cancel(),、isCancel(),、isDone()四種方法,表示Future有三種功能:

1,、判斷任務(wù)是否完成

2,、中斷任務(wù)

3、獲取任務(wù)執(zhí)行結(jié)果

FutureTask

FutureTask是Future的實(shí)現(xiàn)類,,它提供了對(duì)Future的基本實(shí)現(xiàn),。可使用FutureTask包裝Callable或Runnable對(duì)象,,因?yàn)镕utureTask實(shí)現(xiàn)了Runnable,,所以也可以將FutureTask提交給Executor。

使用方法

Callable,、Future,、FutureTask一般都是和線程池配合使用的,因?yàn)榫€程池ThreadPoolExecutor的父類AbstractExecutorService提供了三種submit方法:

1,、public Future<?> subit(Runnable task){...}

2,、public <T> Future<T> submit<Runnable task, T result>{...}

3、public <T> Future<T> submit<Callable<T> task>{...}

第2個(gè)用得不多,,第1個(gè)和第3個(gè)比較有用

Callable+Future使用示例

復(fù)制代碼
public static class CallableThread implements Callable<String>
{
    public String call() throws Exception
    {
        System.out.println("進(jìn)入CallableThread的call()方法, 開始睡覺, 睡覺時(shí)間為" + System.currentTimeMillis());
        Thread.sleep(10000);
        return "123";
    }
}
    
public static void main(String[] args) throws Exception
{
    ExecutorService es = Executors.newCachedThreadPool();
    CallableThread ct = new CallableThread();
    Future<String> f = es.submit(ct);
    es.shutdown();
        
    Thread.sleep(5000);
    System.out.println("主線程等待5秒, 當(dāng)前時(shí)間為" + System.currentTimeMillis());
        
    String str = f.get();
    System.out.println("Future已拿到數(shù)據(jù), str = " + str + ", 當(dāng)前時(shí)間為" + System.currentTimeMillis());
}
復(fù)制代碼

運(yùn)行結(jié)果為:

進(jìn)入CallableThread的call()方法, 開始睡覺, 睡覺時(shí)間為1444654421368
主線程等待5秒, 當(dāng)前時(shí)間為1444654426369
Future已拿到數(shù)據(jù), str = 123, 當(dāng)前時(shí)間為1444654431369

看到任意一個(gè)利用Callable接口submit上去的任務(wù),,只要有一個(gè)Future接受它,F(xiàn)uture便可以在程序任何地點(diǎn)嘗試去獲取這條線程返回出去的數(shù)據(jù),,時(shí)間可以比對(duì)一下,,正好10000ms,即10s

Callable+FutureTask使用示例

有興趣的可以看下源碼,,其實(shí)使用Callable+Future的方式,,es.submit(ct)方法返回的Future,底層實(shí)現(xiàn)new出來的是一個(gè)FutureTask,。那么,,我們看一下Callable+FutureTask的方式:

復(fù)制代碼
public static class CallableThread implements Callable<String>
{
    public String call() throws Exception
    {
        System.out.println("進(jìn)入CallableThread的call()方法, 開始睡覺, 睡覺時(shí)間為" + System.currentTimeMillis());
        Thread.sleep(10000);
        return "123";
    }
}
    
public static void main(String[] args) throws Exception
{
    ExecutorService es = Executors.newCachedThreadPool();
    CallableThread ct = new CallableThread();
    FutureTask<String> f = new FutureTask<String>(ct);
    es.submit(f);
    es.shutdown();
        
    Thread.sleep(5000);
    System.out.println("主線程等待5秒, 當(dāng)前時(shí)間為" + System.currentTimeMillis());
        
    String str = f.get();
    System.out.println("Future已拿到數(shù)據(jù), str = " + str + ", 當(dāng)前時(shí)間為" + System.currentTimeMillis());
}
復(fù)制代碼

看下運(yùn)行結(jié)果:

進(jìn)入CallableThread的call()方法, 開始睡覺, 睡覺時(shí)間為1444655049199
主線程等待5秒, 當(dāng)前時(shí)間為1444655054200
Future已拿到數(shù)據(jù), str = 123, 當(dāng)前時(shí)間為1444655059200

和上面的寫法運(yùn)行結(jié)果一樣,,就不解釋了

使用Callable,、Future和FutureTask的好處

上面演示了兩個(gè)例子,其實(shí)反映的是現(xiàn)實(shí)中一種情況,,把上面的例子稍微擴(kuò)展一下就是:

有一個(gè)method()方法,,方法中執(zhí)行方法A返回一個(gè)數(shù)據(jù)要10秒鐘,A方法后面的代碼一共要執(zhí)行20秒鐘,,但是這20秒的代碼中有10秒的方法并不依賴方法A的執(zhí)行結(jié)果,,有10秒鐘的代碼依賴方法A的執(zhí)行結(jié)果,。此時(shí)若采用同步的方式,那么勢(shì)必要先等待10秒鐘,,等待方法A執(zhí)行完畢,,返回?cái)?shù)據(jù),再執(zhí)行后面20秒的代碼,。

不得不說這是一種低效率的做法,。有了Callable、Future和FutureTask,,那么:

1,、先把A方法的內(nèi)容放到Callable實(shí)現(xiàn)類的call()方法中

2、method()方法中,,Callable實(shí)現(xiàn)類傳入Executor的submit方法中

3,、執(zhí)行后面方法中10秒不依賴方法A運(yùn)行結(jié)果的代碼

4、獲取方法A的運(yùn)行結(jié)果,,執(zhí)行后面方法中10秒依賴方法A運(yùn)行結(jié)果的代碼

這樣代碼執(zhí)行效率一下子就提高了,,程序不必卡在A方法處。

當(dāng)然,,也可以不用Callable,,采用實(shí)現(xiàn)Runnable的方式,run()方法執(zhí)行完了想個(gè)辦法給method()方法中的某個(gè)變量V賦個(gè)值就好了,。但是我上一篇文章開頭就說了,,之所以要用多線程組件,就是因?yàn)镴DK幫我們很好地實(shí)現(xiàn)好了代碼細(xì)節(jié),,讓開發(fā)者更多可以關(guān)注業(yè)務(wù)層的邏輯,。如果使用Runnable的方式,那么我們自己就要考慮很多細(xì)節(jié),,比如Runnable實(shí)現(xiàn)類的run()方法執(zhí)行完畢給V賦值是否線程安全,、10秒后如果A方法沒有執(zhí)行完導(dǎo)致V還沒有值怎么辦,何況JDK還給用戶提供了取消任務(wù),、判斷任務(wù)是否存在等方法,。既然JDK已經(jīng)幫我們考慮并實(shí)現(xiàn)這些細(xì)節(jié)了,在沒有有說服力的理由的情況下,,我們?yōu)槭裁催€要自己寫run()方法的實(shí)現(xiàn)呢,? 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多