最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于Future機(jī)制原理及解析

 更新時(shí)間:2022年11月21日 09:21:48   作者:小小少年_  
這篇文章主要介紹了關(guān)于Future機(jī)制原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

future機(jī)制是

在通過線程去執(zhí)行某個(gè)任務(wù)的時(shí)候,如果比較耗時(shí),我們可以通過futureTask機(jī)制,異步返回,繼續(xù)去執(zhí)行其他的任務(wù),在需要獲取執(zhí)行結(jié)果的時(shí)候,通過future.get()方法去獲取,如果任務(wù)沒有執(zhí)行完畢,會(huì)通過lockSupport.park()方法去阻塞主線程,直到run()方法執(zhí)行完畢之后,會(huì)通過lockSupport.unpark()方法去喚醒線程

應(yīng)用

public class FutureTest {
? ? public static void main(String[] args) throws ExecutionException, InterruptedException {
? ? ? ? MyThread myThread = new MyThread();
? ? ? ? FutureTask<String> futureTask = new FutureTask<>(myThread);
? ? ? ? /**
? ? ? ? ?* 同一個(gè)futureTask對象,通過多個(gè)線程進(jìn)行多次調(diào)用,但是只會(huì)執(zhí)行一次
? ? ? ? ?* 如果是計(jì)算的操作,需要進(jìn)行多次計(jì)算操作,需要聲明不同的futureTask對象
? ? ? ? ?*/
? ? ? ? new Thread(futureTask, "A").start();
? ? ? ? new Thread(futureTask, "B").start();
? ? ? ? System.out.println(Thread.currentThread().getName() + "測試,在調(diào)用future.get()方法之前,可以執(zhí)行其他邏輯 ");
? ? ? ? System.out.println(futureTask.get());
? ? ? ? System.out.println("測試futureTask的get方法阻塞");
? ? }
}

class MyThread implements Callable<String> {

? ? @Override
? ? public String call() throws Exception {
? ? ? ? System.out.println(Thread.currentThread().getName() + " 測試callable");
? ? ? ? TimeUnit.SECONDS.sleep(4);
? ? ? ? return "success";
? ? }
}

這里就是模擬thread比較耗時(shí),此時(shí)就可以通過futureTask異步返回之后,在需要使用的時(shí)候,調(diào)用其get方法去獲取執(zhí)行結(jié)果,如果call()方法還沒有執(zhí)行完,那futureTask.get()方法會(huì)一直阻塞,直到線程執(zhí)行完畢,獲取到執(zhí)行結(jié)果

原理

我們先說future.get()是如何阻塞的,也就是說在線程對應(yīng)的方法還未執(zhí)行完時(shí),主線程如何去阻塞?

在源碼中,有一個(gè)重要的屬性

private volatile int state;
? ? /**
? ? ?* 在構(gòu)造函數(shù)中,設(shè)置為new
? ? ?*/
? ? private static final int NEW ? ? ? ? ?= 0;
? ? /**
? ? ?* 線程正常執(zhí)行完畢,通過CAS將state修改為completing
? ? ?*/
? ? private static final int COMPLETING ? = 1;
? ? /**
? ? ?*
? ? ?*/
? ? private static final int NORMAL ? ? ? = 2;
? ? /**
? ? ?* 執(zhí)行線程的時(shí)候,如果拋出異常,通過cas修改為exceptional
? ? ?*/
? ? private static final int EXCEPTIONAL ?= 3;
? ? /**
? ? ?* 如果調(diào)用了cancel(boolean mayInterruptIfRunning)方法
? ? ?* 入?yún)⒌膍ayInterruptIfRunning為true,就通過cas將state設(shè)置為INTERRUPTING
? ? ?* 如果為false,就通過cas將state修改為cancelled
? ? ?*/
? ? private static final int CANCELLED ? ?= 4;
? ? private static final int INTERRUPTING = 5;
? ? /**
? ? ?* 在調(diào)用cancel()方法,入?yún)閠rue的情況下,如果中斷成功,通過cas將state從
? ? ?* INTERRUPTING修改為INTERRUPTED
? ? ?*/
? ? private static final int INTERRUPTED ?= 6;

接著來說get()方法

get()

可以看到,在get()方法中,會(huì)先判斷當(dāng)前state是否小于等于 COMPLETING,如果是,就去阻塞

/**
? ? ?* @throws CancellationException {@inheritDoc}
? ? ?* 在調(diào)用future.get()方法的時(shí)候,如果線程的run()沒有執(zhí)行完畢,主線程會(huì)等待,直到run()方法正確的執(zhí)行完畢
? ? ?* 在內(nèi)部,是通過lockSupport.park()方法去阻塞線程的
? ? ?* 在該機(jī)制中,涉及到一個(gè)state狀態(tài)標(biāo)識
? ? ?*/
? ? public V get() throws InterruptedException, ExecutionException {
? ? ? ? int s = state;
? ? ? ? if (s <= COMPLETING)
? ? ? ? ? ? s = awaitDone(false, 0L);
? ? ? ? return report(s);
? ? }

對于get方法來說,最為核心的邏輯是在awaitDone()方法中,在該方法中,會(huì)調(diào)用lockSupport.park(this),去阻塞當(dāng)前線程;

所以,我們可以知道,如果主線程在調(diào)用future.get()方法的時(shí)候,假如此時(shí)run()方法還沒有執(zhí)行完畢,會(huì)阻塞當(dāng)前線程,那阻塞之后,總要有一個(gè)地方去喚起,在run()方法正常執(zhí)行完畢之后,會(huì)喚醒當(dāng)前阻塞的線程,繼續(xù)執(zhí)行業(yè)務(wù)邏輯

run()

public void run() {
? ? ? ? /**
? ? ? ? ?* 1.校驗(yàn)當(dāng)前state是否是new狀態(tài)且通過cas設(shè)置當(dāng)前線程成功
? ? ? ? ?*/
? ? ? ? if (state != NEW ||
? ? ? ? ? ? !UNSAFE.compareAndSwapObject(this, runnerOffset,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?null, Thread.currentThread()))
? ? ? ? ? ? return;
? ? ? ? try {
? ? ? ? ? ? Callable<V> c = callable;
? ? ? ? ? ? /**
? ? ? ? ? ? ?* 2.校驗(yàn)當(dāng)前線程中的callable是否有效且state為new
? ? ? ? ? ? ?*/
? ? ? ? ? ? if (c != null && state == NEW) {
? ? ? ? ? ? ? ? V result;
? ? ? ? ? ? ? ? boolean ran;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? ? ? ?* 2.1 執(zhí)行call()方法,如果正常執(zhí)行完畢,設(shè)置ran為true
? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? ? ? result = c.call();
? ? ? ? ? ? ? ? ? ? ran = true;
? ? ? ? ? ? ? ? } catch (Throwable ex) {
? ? ? ? ? ? ? ? ? ? result = null;
? ? ? ? ? ? ? ? ? ? ran = false;
? ? ? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? ? ? ?* 2.2 假如執(zhí)行報(bào)錯(cuò),被捕獲到,在setException方法中,也會(huì)去喚醒阻塞的線程
? ? ? ? ? ? ? ? ? ? ?*/
? ? ? ? ? ? ? ? ? ? setException(ex);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? ?* 3.如果ran為true,就調(diào)用set方法,在set方法中,有一步跟重要的操作,就是通過lockSupport.unpark()喚醒線程
? ? ? ? ? ? ? ? ?*/
? ? ? ? ? ? ? ? if (ran)
? ? ? ? ? ? ? ? ? ? set(result);
? ? ? ? ? ? }
? ? ? ? } finally {
? ? ? ? ? ? // runner must be non-null until state is settled to
? ? ? ? ? ? // prevent concurrent calls to run()
? ? ? ? ? ? runner = null;
? ? ? ? ? ? // state must be re-read after nulling runner to prevent
? ? ? ? ? ? // leaked interrupts
? ? ? ? ? ? int s = state;
? ? ? ? ? ? if (s >= INTERRUPTING)
? ? ? ? ? ? ? ? handlePossibleCancellationInterrupt(s);
? ? ? ? }
? ? }

在這里的run()方法中,setException和set(result)方法中,都會(huì)調(diào)用一個(gè)方法:finishCompletion()

set()

?? ?/*
?? ?* 在set方法中,會(huì)通過cas更新當(dāng)前的state狀態(tài)
? ? ?* 然后在調(diào)用finishCompletion的時(shí)候,會(huì)喚醒阻塞的線程
? ? ?* @param v the value
? ? ?*/
? ? protected void set(V v) {
? ? ? ? if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
? ? ? ? ? ? outcome = v;
? ? ? ? ? ? UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
? ? ? ? ? ? finishCompletion();
? ? ? ? }
? ? }

在線程正常執(zhí)行完之后,會(huì)通過cas將state的狀態(tài)從new修改為completing,然后再修改為normal

finishCompletion()

/**
? ? ?* Removes and signals all waiting threads, invokes done(), and
? ? ?* nulls out callable.
? ? ?* 這個(gè)方法大致的意思是:從等待隊(duì)列中獲取到當(dāng)前在等待的線程信息,然后通過cas將q設(shè)置為null
? ? ?* 最后會(huì)通過lockSupport.unPark()方法喚醒線程
? ? ?*/
? ? private void finishCompletion() {
? ? ? ? // assert state > COMPLETING;
? ? ? ? /**
? ? ? ? ?* 1.從waiters中獲取到等待的節(jié)點(diǎn)
? ? ? ? ?*/
? ? ? ? for (WaitNode q; (q = waiters) != null;) {
? ? ? ? ? ? /**
? ? ? ? ? ? ?* 2.通過cas將q設(shè)置為null
? ? ? ? ? ? ?*/
? ? ? ? ? ? if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
? ? ? ? ? ? ? ? for (;;) {
? ? ? ? ? ? ? ? ? ? Thread t = q.thread;
? ? ? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? ? ? ?* 3.喚醒線程
? ? ? ? ? ? ? ? ? ? ?*/
? ? ? ? ? ? ? ? ? ? if (t != null) {
? ? ? ? ? ? ? ? ? ? ? ? q.thread = null;
? ? ? ? ? ? ? ? ? ? ? ? LockSupport.unpark(t);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? WaitNode next = q.next;
? ? ? ? ? ? ? ? ? ? if (next == null)
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? q.next = null; // unlink to help gc
? ? ? ? ? ? ? ? ? ? q = next;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? done();

? ? ? ? callable = null; ? ? ? ?// to reduce footprint
? ? }

這個(gè)方法也不需要做過多解釋了,就是從waitNode中,獲取到當(dāng)前等待的線程,然后喚醒

總結(jié)

所以:對于future.get()方法,如果run()方法沒有執(zhí)行完成,該方法會(huì)阻塞線程,并且在方法正常執(zhí)行完畢之后,喚醒阻塞的線程,繼續(xù)去執(zhí)行對應(yīng)的業(yè)務(wù)代碼

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于FeignException$InternalServerError的解決方案

    基于FeignException$InternalServerError的解決方案

    這篇文章主要介紹了FeignException$InternalServerError的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • form-data與x-www-form-urlencoded的區(qū)別以及知識延伸

    form-data與x-www-form-urlencoded的區(qū)別以及知識延伸

    這篇文章主要給大家介紹了關(guān)于form-data與x-www-form-urlencoded的區(qū)別以及知識延伸,form-data和x-www-form-urlencoded都是HTTP請求中用于傳輸表單數(shù)據(jù)的編碼格式,需要的朋友可以參考下
    2023-11-11
  • mybatis-plus 批量插入示例代碼

    mybatis-plus 批量插入示例代碼

    正常我們使用mybatis-plus插入的時(shí)候,首先想到的是saveBatch方法,不過看了下打印出來的sql和底層代碼,才發(fā)現(xiàn)它并不是真正的批量插入這篇文章主要介紹了mybatis-plus 批量插入示例,需要的朋友可以參考下
    2023-07-07
  • Java持久層框架Mybatis入門詳細(xì)教程

    Java持久層框架Mybatis入門詳細(xì)教程

    Mybatis持久層框架支持自定義SQL、存儲過程以及高級映射,可以通過XML或注解來配置和映射原始類型、接口和Java POJOs為數(shù)據(jù)庫中的記錄,接下來通過本文給大家介紹Java持久層框架Mybatis入門詳細(xì)教程,一起學(xué)習(xí)下吧
    2021-06-06
  • springCloud中的Sidecar多語言支持詳解

    springCloud中的Sidecar多語言支持詳解

    這篇文章主要介紹了springCloud中的Sidecar多語言支持詳解,Sidecar是將一組緊密結(jié)合的任務(wù)與主應(yīng)用程序共同放在一臺主機(jī)Host中,但會(huì)將它們部署在各自的進(jìn)程或容器中,需要的朋友可以參考下
    2024-01-01
  • Java 實(shí)戰(zhàn)項(xiàng)目錘煉之在線蛋糕商城系統(tǒng)的實(shí)現(xiàn)

    Java 實(shí)戰(zhàn)項(xiàng)目錘煉之在線蛋糕商城系統(tǒng)的實(shí)現(xiàn)

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+jdbc+mysql實(shí)現(xiàn)一個(gè)在線蛋糕商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • 詳解Java中Thread 和Runnable區(qū)別

    詳解Java中Thread 和Runnable區(qū)別

    這篇文章主要介紹了Java中Thread 和Runnable的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java?Spring框架的注解式開發(fā)你了解嗎

    Java?Spring框架的注解式開發(fā)你了解嗎

    這篇文章主要為大家詳細(xì)介紹了Spring框架的注解式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)與算法之稀疏數(shù)組與隊(duì)列深入理解

    Java數(shù)據(jù)結(jié)構(gòu)與算法之稀疏數(shù)組與隊(duì)列深入理解

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之稀疏數(shù)組與隊(duì)列深入理解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • JVM完全解讀之YGC來龍去脈分析

    JVM完全解讀之YGC來龍去脈分析

    YGC是JVM?GC當(dāng)前最為頻繁的一種GC,一個(gè)高并發(fā)的服務(wù)在運(yùn)行期間,會(huì)進(jìn)行大量的YGC,發(fā)生YGC時(shí),會(huì)進(jìn)行STW,一般時(shí)間都很短,除非碰到Y(jié)GC時(shí),存在大量的存活對象需要進(jìn)行拷貝
    2022-01-01

最新評論

隆林| 榆社县| 柳林县| 长子县| 航空| 济源市| 贵南县| 象山县| 出国| 辉县市| 民乐县| 逊克县| 南昌县| 谢通门县| 莱阳市| 革吉县| 会宁县| 垦利县| 徐闻县| 余庆县| 博湖县| 望都县| 新闻| 大连市| 新巴尔虎右旗| 盱眙县| 淮北市| 海城市| 民丰县| 汽车| 垫江县| 兴义市| 米易县| 通州市| 营口市| 红河县| 天柱县| 营山县| 宁波市| 温宿县| 长岭县|