成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

FutureTask

GeekGhc / 826人閱讀

摘要:可取消的異步計(jì)算。只有在計(jì)算完成后才能檢索結(jié)果如果計(jì)算還沒(méi)有完成,方法將會(huì)被阻塞。任務(wù)正常執(zhí)行結(jié)束。任務(wù)執(zhí)行過(guò)程中發(fā)生異常。任務(wù)即將被中斷。運(yùn)行完成后將會(huì)清空。根據(jù)執(zhí)行結(jié)果設(shè)置狀態(tài)。

FutureTask What is it

? 可取消的異步計(jì)算。該類提供了 Future的基本實(shí)現(xiàn),其中包括啟動(dòng)和取消計(jì)算的方法,查詢計(jì)算是否完成以及檢索計(jì)算結(jié)果的方法。只有在計(jì)算完成后才能檢索結(jié)果;如果計(jì)算還沒(méi)有完成,{getcode}方法將會(huì)被阻塞。一旦計(jì)算完成,計(jì)算不能被重新啟動(dòng)或取消(除非計(jì)算是使用調(diào)用的runAndReset()。

? 該類實(shí)現(xiàn)自RunableFuture接口,其中RunableFuture接口又繼承自Runable和Future。所以可以理解為:FutureTask是一個(gè)可以計(jì)算Future結(jié)果的一個(gè)Future實(shí)現(xiàn),

How to use

由于FutureTask間接或直接實(shí)現(xiàn)了Runable和Future接口,所以其具有如下特征:

可以像一個(gè)普通的任務(wù)一樣,使用線程池提交一個(gè)任務(wù)并執(zhí)行。

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new FutureTask(new Callable() {
    @Override
    public Integer call() throws Exception {
          return 100;
    }
}));

可以像一個(gè)普通的任務(wù)一樣,使用Thread來(lái)執(zhí)行,但可以異步獲取結(jié)果。

 FutureTask futureTask = new FutureTask(new Callable() {
   @Override
   public Integer call() throws Exception {
      return 100;
   }
});
new Thread(futureTask).start();
futureTask.get();

When to use

考慮一種使用Cache的場(chǎng)景:一般情況下,對(duì)于熱點(diǎn)數(shù)據(jù)我們都會(huì)使用cache保存數(shù)據(jù),只有當(dāng)cache失效了,才會(huì)進(jìn)行耗時(shí)的網(wǎng)絡(luò)調(diào)用或者數(shù)據(jù)庫(kù)查詢。但是當(dāng)cache失效時(shí),同時(shí)有多個(gè)該key的查詢,那么在短時(shí)間內(nèi)可能會(huì)有多個(gè)相同的耗時(shí)查詢,瞬間對(duì)系統(tǒng)性能會(huì)有一定的損失,為了解決這種情況可以采取緩存FutureTask的方式解決:

思路借鑒:https://github.com/javacreed/...

//獲取緩存的客戶端
public class CacheClient {
    public static  T getCache(int id){
        return null;
    }
}
//Service層邏輯
public class CacheService {
    private static ConcurrentMap> cacheFuture = new ConcurrentHashMap<>();
    public User getUserInfo(int id) {
        Future future = createFutureIfAbsent(id);
        try {
            return future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
    private Future createFutureIfAbsent(final int id) {
        Future future = cacheFuture.get(id);
        if (future == null) {
            FutureTask futureTask = new FutureTask(new Callable() {
                @Override
                public User call() throws Exception {
                    return CacheClient.getCache(id);
                }
            });
            future = cacheFuture.putIfAbsent(id, futureTask);
            if (future == null) {
                future = futureTask;
                futureTask.run();
            }
        }
        return future;
    }
    public class User {
        private int id;
        private String name;
        private String age;
        。。。
    }
}
How to design
狀態(tài)機(jī)

? FutureTask作為一個(gè)可運(yùn)行的Future,其運(yùn)行過(guò)程中存在狀態(tài)的遷移過(guò)程,F(xiàn)utureTask的運(yùn)行狀態(tài)有:

NEW:初始狀態(tài)。

COMPLETING:結(jié)果正在被set過(guò)程中。

NORMAL:任務(wù)正常執(zhí)行結(jié)束。

EXCEPTIONAL:任務(wù)執(zhí)行過(guò)程中發(fā)生異常。

CANCELLED:任務(wù)執(zhí)行過(guò)程中被取消。

INTERRUPTING:任務(wù)即將被中斷。

INTERRUPTED:任務(wù)已經(jīng)被中斷。

狀態(tài)躍遷:

正常結(jié)束:NEW->COMPLETING->NORMAL

出現(xiàn)異常:NEW->COMPLETING->EXCEPTIONAL

任務(wù)被取消且不響應(yīng)中斷:NEW->CANCELLED

任務(wù)被取消且響應(yīng)中斷:NEW->INTERRUPTING->INTERRUPTED

成員變量

state:指示當(dāng)前任務(wù)執(zhí)行的狀態(tài)。

callback:需要被運(yùn)行的任務(wù)。運(yùn)行完成后將會(huì)清空。

outcome:保存任務(wù)執(zhí)行之后的結(jié)果。

runner:持有任務(wù)執(zhí)行過(guò)程中運(yùn)行線程。

waiters:等待線程的堆棧[稍后將做詳細(xì)分析]。

構(gòu)造方法
public FutureTask(Callable callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
}

FutureTask有兩個(gè)構(gòu)造方法,雖然兩個(gè)構(gòu)造方法的入?yún)⒙杂胁煌?,但是在底層?zhí)行時(shí)都是按照Callback任務(wù)來(lái)構(gòu)建的。并在此過(guò)程初始化當(dāng)前的任務(wù)狀態(tài)為:NEW

核心方法

下面將從核心方法開(kāi)始,逐漸分析FutureTask的原理:

run():任務(wù)執(zhí)行

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

該方法的邏輯很簡(jiǎn)單,主要完成了如下任務(wù):

1.首先判斷任務(wù)的有效性:1)該任務(wù)的狀態(tài)是否為初始狀態(tài):NEW,2)把運(yùn)行任務(wù)的線程設(shè)置給成員變量runner。

2.執(zhí)行任務(wù)。

3.根據(jù)執(zhí)行結(jié)果設(shè)置狀態(tài)。

get()/get(long timeout, TimeUnit unit)

public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
 }```

該方法的邏輯更簡(jiǎn)單:首先判斷當(dāng)前的狀態(tài),然后就會(huì)調(diào)用awaitDone()方法等待結(jié)果,當(dāng)?shù)却瑫r(shí)就會(huì)拋出TimeOutException,否則調(diào)用report()將結(jié)果報(bào)告出去。下面看看等待結(jié)果是如何處理的:

private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
          //首先計(jì)算出該任務(wù)的最終結(jié)束時(shí)間
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            //判斷當(dāng)前線程是否被中斷
            if (Thread.interrupted()) {
                  //從等待隊(duì)列中刪除該線程的等待節(jié)點(diǎn)
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            //如果狀態(tài)>COMPLETING,說(shuō)明任務(wù)已經(jīng)結(jié)束了,不管是否正常結(jié)束,都是可以返回的
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
              //如果當(dāng)前狀態(tài)還是COMPLETING,說(shuō)明結(jié)果來(lái)沒(méi)有返回呢,那就讓出CPU
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            //如果當(dāng)前任務(wù)還沒(méi)有生成等待節(jié)點(diǎn),那么就創(chuàng)建一個(gè)以當(dāng)前線程的等待節(jié)點(diǎn)。
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
            //采用頭插法構(gòu)建等待隊(duì)列
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                  //任務(wù)執(zhí)行超時(shí)了,那么就刪除等待隊(duì)列
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                  //還沒(méi)有超時(shí),那么就將當(dāng)前線程park
                LockSupport.parkNanos(this, nanos);
            }
            else
                LockSupport.park(this);
        }
 

該方法雖然篇幅很大,但是完成的任務(wù)也是很簡(jiǎn)單的,主要可以總結(jié)如下:

首先判斷在超時(shí)時(shí)間內(nèi),任務(wù)是否執(zhí)行完成(失?。?。

通過(guò)狀態(tài)為判斷任務(wù)是否執(zhí)行完成或失敗。

? NOTE:為什么要使用這個(gè)waiter?[多帶帶文章分析:]

Conclusion

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/68154.html

相關(guān)文章

  • 追蹤解析 FutureTask 源碼

    摘要:零前期準(zhǔn)備文章異常啰嗦且繞彎。版本版本簡(jiǎn)介是中默認(rèn)的實(shí)現(xiàn)類,常與結(jié)合進(jìn)行多線程并發(fā)操作。所以方法的主體其實(shí)就是去喚醒被阻塞的線程。本文僅為個(gè)人的學(xué)習(xí)筆記,可能存在錯(cuò)誤或者表述不清的地方,有緣補(bǔ)充 零 前期準(zhǔn)備 0 FBI WARNING 文章異常啰嗦且繞彎。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 ThreadLocal 簡(jiǎn)介 ...

    xcc3641 評(píng)論0 收藏0
  • 【Java并發(fā)】Runnable、Callable、Future、FutureTask

    摘要:聲明了幾種方法,其中有一個(gè)就是傳入聲明了對(duì)具體的或者任務(wù)執(zhí)行進(jìn)行取消查詢結(jié)果獲取等方法。事實(shí)上,是接口的一個(gè)唯一實(shí)現(xiàn)類。使用示例第一種方式是使用繼承了的線程池中的方法,將直接提交創(chuàng)建。 創(chuàng)建線程的兩種方式 直接繼承 Thread 實(shí)現(xiàn) Runnable 接口 這兩種方式都有一個(gè)缺點(diǎn):在執(zhí)行完成任務(wù)之后,無(wú)法直接獲取到最后的執(zhí)行結(jié)果。如果需要獲取執(zhí)行結(jié)果,就必須通過(guò)共享變量或線程通...

    zhaot 評(píng)論0 收藏0
  • Java多線程-Callable和Future

    摘要:類提供了一些有用的方法在線程池中執(zhí)行內(nèi)的任務(wù)。在線程池提交任務(wù)后返回了一個(gè)對(duì)象,使用它可以知道任務(wù)的狀態(tài)和得到返回的執(zhí)行結(jié)果。 Callable和Future出現(xiàn)的原因 創(chuàng)建線程的2種方式,一種是直接繼承Thread,另外一種就是實(shí)現(xiàn)Runnable接口。 這2種方式都有一個(gè)缺陷就是:在執(zhí)行完任務(wù)之后無(wú)法獲取執(zhí)行結(jié)果。 如果需要獲取執(zhí)行結(jié)果,就必須通過(guò)共享變量或者使用線程通信的方式來(lái)達(dá)...

    seasonley 評(píng)論0 收藏0
  • CountDownLatch + Callbale+FutureTask 實(shí)現(xiàn)異步變同步調(diào)用

    摘要:背景通過(guò)接口實(shí)現(xiàn)調(diào)用發(fā)送數(shù)據(jù),接口返回值為發(fā)送數(shù)據(jù)的對(duì)應(yīng)結(jié)果。接口為同步阻塞,為異步回調(diào)方式。接收數(shù)據(jù)回調(diào)接收到數(shù)據(jù)后,通過(guò)閉鎖釋放阻塞的線程,同時(shí)設(shè)置結(jié)果返回給調(diào)用者 背景 通過(guò)HTTP接口實(shí)現(xiàn)調(diào)用MQTT Client發(fā)送數(shù)據(jù),HTTP接口返回值為MQTT Client發(fā)送數(shù)據(jù)的對(duì)應(yīng)結(jié)果。 HTTP接口為同步阻塞,MQTT Client 為異步回調(diào)方式。如何實(shí)現(xiàn)在HTTP接口中調(diào)用...

    張金寶 評(píng)論0 收藏0
  • java并發(fā)編程學(xué)習(xí)之FutureTask

    摘要:在并發(fā)編程學(xué)習(xí)之三種線程啟動(dòng)方式中有提過(guò)。是否執(zhí)行結(jié)束,包括正常執(zhí)行結(jié)束或異常結(jié)束。獲取返回值,沒(méi)有得到返回值前一直阻塞。運(yùn)行結(jié)果如下由于任務(wù)被取消,所以拋出異常。注意的是,此時(shí)線程還在跑,和返回的是。并不能讓任務(wù)真正的結(jié)束。 FutureTask 在java并發(fā)編程學(xué)習(xí)之三種線程啟動(dòng)方式中有提過(guò)。主要的方法如下: cancel(boolean mayInterruptIfRunni...

    BothEyes1993 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<