成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

java并發(fā)編程學(xué)習(xí)2--Future

weizx / 646人閱讀

摘要:一個(gè)線程池包含很多準(zhǔn)備運(yùn)行的空閑線程,每當(dāng)執(zhí)行完畢后,線程不會死亡而是回到線程池準(zhǔn)備為下一個(gè)請求提供服務(wù)。另一個(gè)使用線程池的理由是減少并發(fā)線程數(shù)。創(chuàng)建大量線程會大大降低性能甚至拖垮虛擬機(jī)。

【Future的概念

interface Future ,表示異步計(jì)算的結(jié)果,F(xiàn)uture有個(gè)get方法而獲取結(jié)果只有在計(jì)算完成時(shí)獲取,否則會一直阻塞直到任務(wù)轉(zhuǎn)入完成狀態(tài),然后會返回結(jié)果或者拋出異常。相對于繼承Thread來創(chuàng)建線程方式,使用Runnable可以讓你的實(shí)現(xiàn)類同時(shí)實(shí)現(xiàn)多個(gè)接口,而相對于Callable及Future,Runnable方法并不返回任務(wù)執(zhí)行結(jié)果且不能拋出異常。

【interface Future 具有如下方法
public interface Future {
    //取消計(jì)算,如果尚未開始,直接取消不再運(yùn)算,如果正在進(jìn)行:mayInterruptIfRunning等于true就會被中斷。注意一點(diǎn):只要調(diào)用了cancle(),無論任務(wù)是否能夠執(zhí)行,再調(diào)用get()都會出現(xiàn)cancledException,這是由于Future.state的狀態(tài)被置為CANCELLED = 4,所致的;
    boolean cancel(boolean mayInterruptIfRunning)
    //判斷計(jì)算是否取消。
    boolean isCancelled();
    //判斷計(jì)算是否完成,如果計(jì)算完成返回true,否則返回false
    boolean isDone();
    //獲得異步計(jì)算的結(jié)果,如果在調(diào)用get()的時(shí)候結(jié)果還沒有計(jì)算出來,調(diào)用線程將被阻塞。
    V get() throws InterruptedException, ExecutionException;
    //獲得異步計(jì)算的結(jié)果,如果在調(diào)用get()的時(shí)候結(jié)果還沒有計(jì)算出來,調(diào)用線程將被阻塞。如果調(diào)用超時(shí)將會拋出TimeoutException。
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

補(bǔ)充:

   - FutureTask:包裝器,可以將Callable轉(zhuǎn)換成為Future與Runnable,它同時(shí)實(shí)現(xiàn)了二者的接口。
   - Callable:可以為異步方法返回計(jì)算結(jié)果。
   
【下面我們實(shí)現(xiàn)一種基于Future的場景
public class Exercise {

       private SimpleApplicationService simpleApplicationService = new SimpleApplicationService();

       @Test
       public void futureTest() throws InterruptedException, ExecutionException {
           long st = System.currentTimeMillis();
           //這里本是一callable接口實(shí)現(xiàn),我用lambda方便一點(diǎn)
           FutureTask result = new FutureTask(() -> simpleApplicationService.query());
           //記住我們的任務(wù)都與需要開啟一個(gè)新的線程
           Thread t = new Thread(result);
           t.start();
           long end = System.currentTimeMillis();
           System.out.println("耗時(shí):" + (end - st) + " 結(jié)果:" + result.get());
       }
   }

   public class SimpleApplicationService {
       public String query() throws InterruptedException {
           System.out.println("開始查詢");
           Thread.sleep(2000);
           return "query result";
       }
   }
【反思一些問題:

每個(gè)異步方法都需要新開啟一個(gè)線程這樣很消耗資源。

每次都要new一個(gè)thread挺麻煩的。

【解決方案:使用線程池

構(gòu)建一個(gè)新的線程是有代價(jià)的,因?yàn)樵O(shè)計(jì)到與操作系統(tǒng)的交互。如果程序中創(chuàng)建了大量的并且生命周期很短的線程,我們應(yīng)該使用線程池。
一個(gè)線程池包含很多準(zhǔn)備運(yùn)行的空閑線程,每當(dāng)run()執(zhí)行完畢后,線程不會死亡而是回到線程池準(zhǔn)備為下一個(gè)請求提供服務(wù)。

另一個(gè)使用線程池的理由是減少并發(fā)線程數(shù)。創(chuàng)建大量線程會大大降低性能甚至拖垮虛擬機(jī)。

【Executor介紹

Executors類有許多靜態(tài)方法可創(chuàng)建線程池。例如:

Executors.newCachedThreadPool():對于一個(gè)任務(wù),有空閑線程可用則會立即執(zhí)行,否則創(chuàng)建一個(gè)新的線程??臻e線程存活60s。

Executors.newFixedThreadPool(n):構(gòu)建具有固定大小的線程池,若任務(wù)多余空閑線程數(shù),則將多余任務(wù)放置等待隊(duì)列中。

Executors.newSingleThreadExecutor():只有一個(gè)空閑線程的線程池,任務(wù)執(zhí)行一個(gè)接一個(gè);

以上三個(gè)方法返回ExecutorService接口的ThreadPoolExecutor對象。

核心(簡介):

ThreadPoolExecutor

    public class ThreadPoolExecutor extends AbstractExecutorService {

        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue workQueue);

        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue workQueue,ThreadFactory threadFactory);

        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                BlockingQueue workQueue,RejectedExecutionHandler handler);

        //事實(shí)上,前面三個(gè)構(gòu)造器都是調(diào)用的第四個(gè)構(gòu)造器進(jìn)行的初始化工作。
        public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);

    }
    

參數(shù)含義:

corePoolSize:核心池的大小,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法。從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0。當(dāng)有任務(wù)來之后,就會創(chuàng)建一個(gè)線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后,就會把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中;

maximumPoolSize:線程池最大線程數(shù),這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個(gè)線程;

keepAliveTime:表示線程沒有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會終止。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),keepAliveTime才會起作用。直到線程池中的線程數(shù)不大于corePoolSize,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會終止,直到線程池中的線程數(shù)不超過corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會起作用,直到線程池中的線程數(shù)為0;

unit:參數(shù)keepAliveTime的時(shí)間單位

workQueue:一個(gè)阻塞隊(duì)列,用來存儲等待執(zhí)行的任務(wù),這個(gè)參數(shù)的選擇也很重要,會對線程池的運(yùn)行過程產(chǎn)生重大影響,一般來說,這里的阻塞隊(duì)列有以下幾種選擇:

   - ArrayBlockingQueue
   - LinkedBlockingQueue
   - SynchronousQueue;

threadFactory:線程工廠,主要用來創(chuàng)建線程;

handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略,有以下四種取值:

          - ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
          - ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。
          - ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
          - ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
          

使用連接池應(yīng)該做的事:

 1. 調(diào)用Executors的靜態(tài)方法創(chuàng)建線程池。
 2. 調(diào)用submit(),提交一個(gè)Callable對象或者Runnable對象。
 3. 保存好獲得的Future<>對象,其中是計(jì)算結(jié)果(如果提交的是Callable)。
 4. 沒有任何任務(wù)再提交的時(shí)候使用shutDown()。
 

 public class TaskExercise {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //future + callable
            ExecutorService executor = Executors.newCachedThreadPool();
            CallTask callTask = new CallTask();
            Future taskReturn = executor.submit(callTask);
            System.out.println(taskReturn.get());
            //futureTask
            FutureTask futureTask = new FutureTask(callTask);
            executor.submit(futureTask);
            System.out.println(futureTask.get());
            //runable
            Runnable runTask = new RunTask();
            String result = "xz";
            Future runTaskReturn = executor.submit(runTask,result);
            System.out.println(runTaskReturn.get());

            executor.shutdown();
        }
    }
    class CallTask implements Callable{
        @Override
        public String call() throws Exception {
            return "task return";
        }
    }
    class RunTask implements Runnable{
        @Override
        public void run() {
            System.out.println("run");
        }
    }
    
【控制任務(wù)組

有時(shí)使用執(zhí)行器更有意義的場景是控制一組相關(guān)任務(wù)。

1. shutdownNow():取消所有任務(wù)
2. invokeAny():提交所有對象到一個(gè)Callable對象集合,并返回某個(gè)已完成的任務(wù)結(jié)果。例如:如果你愿意接受任何一種解決方案的話。
3. 還有其他一些方法等我們真正用到時(shí)再學(xué)習(xí)好了~
【補(bǔ)充

spring中實(shí)現(xiàn)異步調(diào)用:spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持。通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用。也就是說調(diào)用者會在調(diào)用時(shí)立即返回,而被調(diào)用方法的實(shí)際執(zhí)行是交給Spring的TaskExecutor來完成。如果是有返回值的話記得:接口返回Future<>,實(shí)現(xiàn)返回AsyncResult<>。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70902.html

相關(guān)文章

  • Java 多線程并發(fā)編程面試筆錄一覽

    摘要:創(chuàng)建線程的方式方式一將類聲明為的子類。將該線程標(biāo)記為守護(hù)線程或用戶線程。其中方法隱含的線程為父線程?;謴?fù)線程,已過時(shí)。等待該線程銷毀終止。更多的使當(dāng)前線程在鎖存器倒計(jì)數(shù)至零之前一直等待,除非線 知識體系圖: showImg(https://segmentfault.com/img/bVbef6v?w=1280&h=960); 1、線程是什么? 線程是進(jìn)程中獨(dú)立運(yùn)行的子任務(wù)。 2、創(chuàng)建線...

    bitkylin 評論0 收藏0
  • 2018年第18周-Java語言思想-并發(fā)

    摘要:某些編程語言被設(shè)計(jì)為可以將并發(fā)任務(wù)彼此隔離,這些語言通常被稱為函數(shù)性語言。通過使用多線程機(jī)制,這些獨(dú)立任務(wù)也被稱為子任務(wù)中的每一個(gè)都將由執(zhí)行線程來驅(qū)動。 并發(fā) 之前學(xué)的都是順序編程的知識,學(xué)習(xí)并發(fā)編程就好像進(jìn)入了一個(gè)全新的領(lǐng)域,有點(diǎn)類似于學(xué)習(xí)了一門新的編程語言,或者至少是學(xué)習(xí)了一整套新的語言概念。要理解并發(fā)編程,其難度與理解面向?qū)ο缶幊滩畈欢唷H绻c(diǎn)兒功夫,就能明白其基本機(jī)制,但想要...

    JouyPub 評論0 收藏0
  • Java并發(fā)

    摘要:對象改變條件對象當(dāng)前線程要等待線程終止之后才能從返回。如果線程在上的操作中被中斷,通道會被關(guān)閉,線程的中斷狀態(tài)會被設(shè)置,并得到一個(gè)。清除線程的中斷狀態(tài)。非公平性鎖雖然可能造成饑餓,但極少的線程切換,保證其更大的吞吐量。 聲明:Java并發(fā)的內(nèi)容是自己閱讀《Java并發(fā)編程實(shí)戰(zhàn)》和《Java并發(fā)編程的藝術(shù)》整理來的。 showImg(https://segmentfault.com/im...

    SKYZACK 評論0 收藏0
  • Java多線程學(xué)習(xí)(七)并發(fā)編程中一些問題

    摘要:相比與其他操作系統(tǒng)包括其他類系統(tǒng)有很多的優(yōu)點(diǎn),其中有一項(xiàng)就是,其上下文切換和模式切換的時(shí)間消耗非常少。因?yàn)槎嗑€程競爭鎖時(shí)會引起上下文切換。減少線程的使用。很多編程語言中都有協(xié)程。所以如何避免死鎖的產(chǎn)生,在我們使用并發(fā)編程時(shí)至關(guān)重要。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)syn...

    dingding199389 評論0 收藏0
  • Java多線程學(xué)習(xí)(七)并發(fā)編程中一些問題

    摘要:因?yàn)槎嗑€程競爭鎖時(shí)會引起上下文切換。減少線程的使用。舉個(gè)例子如果說服務(wù)器的帶寬只有,某個(gè)資源的下載速度是,系統(tǒng)啟動個(gè)線程下載該資源并不會導(dǎo)致下載速度編程,所以在并發(fā)編程時(shí),需要考慮這些資源的限制。 最近私下做一項(xiàng)目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項(xiàng)目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Jav...

    yimo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<