自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java線(xiàn)程池實(shí)現(xiàn)原理與技術(shù),看這一篇就夠了

開(kāi)發(fā) 后端
多線(xiàn)程的軟件設(shè)計(jì)方法確實(shí)可以最大限度地發(fā)揮多核處理器的計(jì)算能力,提高生產(chǎn)系統(tǒng)的吞吐量和性能。但是,若不加控制和管理的隨意使用線(xiàn)程,對(duì)系統(tǒng)的性能反而會(huì)產(chǎn)生不利的影響。

[[261075]]

01.***制線(xiàn)程的缺點(diǎn)

多線(xiàn)程的軟件設(shè)計(jì)方法確實(shí)可以***限度地發(fā)揮多核處理器的計(jì)算能力,提高生產(chǎn)系統(tǒng)的吞吐量和性能。但是,若不加控制和管理的隨意使用線(xiàn)程,對(duì)系統(tǒng)的性能反而會(huì)產(chǎn)生不利的影響。

一種最為簡(jiǎn)單的線(xiàn)程創(chuàng)建和回收的方法類(lèi)似如下:

  1. new Thread(new Runnable() { 
  2.             @Override 
  3.             public void run() { 
  4.                 //do sth 
  5.             } 
  6.         }).start(); 

以上代碼創(chuàng)建了一條線(xiàn)程,并在run()方法結(jié)束后,自動(dòng)回收該線(xiàn)程。在簡(jiǎn)單的應(yīng)用系統(tǒng)中,這段代碼并沒(méi)有太多問(wèn)題。但是在真實(shí)的生產(chǎn)環(huán)境中,系統(tǒng)由于真實(shí)環(huán)境的需要,可能會(huì)開(kāi)啟很多線(xiàn)程來(lái)支撐其應(yīng)用。而當(dāng)線(xiàn)程數(shù)量過(guò)大時(shí),反而會(huì)耗盡CPU和內(nèi)存資源。

首先,雖然與進(jìn)程相比,線(xiàn)程是一種輕量級(jí)的工具,但其創(chuàng)建和關(guān)閉依然需要花費(fèi)時(shí)間,如果為每一個(gè)小的任務(wù)都創(chuàng)建一個(gè)線(xiàn)程,很有可能出現(xiàn)創(chuàng)建和銷(xiāo)毀線(xiàn)程所占用的時(shí)間大于該線(xiàn)程真實(shí)工作所消耗的時(shí)間,反而會(huì)得不償失。

其次,線(xiàn)程本身也是要占用內(nèi)存空間的,大量的線(xiàn)程會(huì)搶占寶貴的內(nèi)部資源。

因此,在實(shí)際生產(chǎn)環(huán)境中,線(xiàn)程的數(shù)量必須得到控制。盲目地大量創(chuàng)建線(xiàn)程對(duì)系統(tǒng)性能是有傷害的。

 

02.簡(jiǎn)單的線(xiàn)程池實(shí)現(xiàn)

下面給出一個(gè)最簡(jiǎn)單的線(xiàn)程池,該線(xiàn)程池不是一個(gè)完善的線(xiàn)程池,但已經(jīng)實(shí)現(xiàn)了一個(gè)基本線(xiàn)程池的核心功能,有助于快速理解線(xiàn)程池的實(shí)現(xiàn)。

1.線(xiàn)程池的實(shí)現(xiàn)

  1. public class ThreadPool { 
  2.     private static ThreadPool instance = null
  3.  
  4.     //空閑的線(xiàn)程隊(duì)列 
  5.     private List<PThread> idleThreads; 
  6.     //已有的線(xiàn)程總數(shù) 
  7.     private int threadCounter; 
  8.     private boolean isShutDown = false
  9.  
  10.     private ThreadPool() { 
  11.         this.idleThreads = new Vector<>(5); 
  12.         threadCounter = 0; 
  13.     } 
  14.  
  15.     public int getCreatedThreadCounter() { 
  16.         return threadCounter; 
  17.     } 
  18.  
  19.     //取得線(xiàn)程池的實(shí)例 
  20.     public synchronized static ThreadPool getInstance() { 
  21.         if (instance == null) { 
  22.             instance = new ThreadPool(); 
  23.         } 
  24.         return instance; 
  25.     } 
  26.  
  27.     //將線(xiàn)程池放入池中 
  28.     protected synchronized void repool(PThread repoolingThread) { 
  29.         if (!isShutDown) { 
  30.             idleThreads.add(repoolingThread); 
  31.         } else { 
  32.             repoolingThread.shutDown(); 
  33.         } 
  34.     } 
  35.  
  36.     //停止池中所有線(xiàn)程 
  37.     public synchronized void shutDown() { 
  38.         isShutDown = true
  39.         for (int threadIndex = 0; threadIndex < idleThreads.size(); threadIndex++) { 
  40.             PThread pThread = idleThreads.get(threadIndex); 
  41.             pThread.shutDown(); 
  42.         } 
  43.     } 
  44.  
  45.     //執(zhí)行任務(wù) 
  46.     public synchronized void start(Runnable target) { 
  47.         PThread thread = null
  48.         //如果有空閑線(xiàn)程,則直接使用 
  49.         if (idleThreads.size() > 0) { 
  50.             int lastIndex = idleThreads.size() - 1; 
  51.             thread = idleThreads.get(lastIndex); 
  52.             idleThreads.remove(thread); 
  53.             //立即執(zhí)行這個(gè)任務(wù) 
  54.             thread.setTarget(target); 
  55.         }//沒(méi)有空閑線(xiàn)程,則創(chuàng)建線(xiàn)程 
  56.         else { 
  57.             threadCounter++; 
  58.             //創(chuàng)建新線(xiàn)程 
  59.             thread = new PThread(target, "PThread #" + threadCounter, this); 
  60.             //啟動(dòng)這個(gè)線(xiàn)程 
  61.             thread.start(); 
  62.         } 
  63.     } 
  64.  

2.要實(shí)現(xiàn)上面的線(xiàn)程池,就需要一個(gè)永不退出的線(xiàn)程與之配合。PThread就是一個(gè)這樣的線(xiàn)程。它的主體部分是一個(gè)***循環(huán),該線(xiàn)程在手動(dòng)關(guān)閉前永不結(jié)束,并一直等待新的任務(wù)到達(dá)。

  1. public class PThread extends Thread { 
  2.     //線(xiàn)程池 
  3.     private ThreadPool pool; 
  4.     //任務(wù) 
  5.     private Runnable target; 
  6.     private boolean isShutDown = false
  7.     private boolean isIdle = false; //是否閑置 
  8.     //構(gòu)造函數(shù) 
  9.     public PThread(Runnable target,String name, ThreadPool pool){ 
  10.         super(name); 
  11.         this.pool = pool; 
  12.         this.target = target; 
  13.     } 
  14.  
  15.     public Runnable getTarget(){ 
  16.         return target; 
  17.     } 
  18.  
  19.     public boolean isIdle() { 
  20.         return isIdle; 
  21.     } 
  22.  
  23.     @Override 
  24.     public void run() { 
  25.         //只要沒(méi)有關(guān)閉,則一直不結(jié)束該線(xiàn)程 
  26.         while (!isShutDown){ 
  27.             isIdle =  false
  28.             if (target != null){ 
  29.                 //運(yùn)行任務(wù) 
  30.                 target.run(); 
  31.             } 
  32.             try { 
  33.                 //任務(wù)結(jié)束了,到閑置狀態(tài) 
  34.                 isIdle = true
  35.                 pool.repool(this); 
  36.                 synchronized (this){ 
  37.                     //線(xiàn)程空閑,等待新的任務(wù)到來(lái) 
  38.                     wait(); 
  39.                 } 
  40.             } catch (InterruptedException e) { 
  41.                 e.printStackTrace(); 
  42.             } 
  43.             isIdle = false
  44.         } 
  45.     } 
  46.  
  47.     public synchronized void setTarget(Runnable newTarget){ 
  48.         target = newTarget; 
  49.         //設(shè)置了任務(wù)之后,通知run方法,開(kāi)始執(zhí)行這個(gè)任務(wù) 
  50.         notifyAll(); 
  51.     } 
  52.  
  53.     //關(guān)閉線(xiàn)程 
  54.     public synchronized void shutDown(){ 
  55.         isShutDown = true
  56.         notifyAll(); 
  57.     } 
  58.  

3.測(cè)試Main方法

  1. public static void main(String[] args) throws InterruptedException { 
  2.        for (int i = 0; i < 1000; i++) { 
  3.            ThreadPool.getInstance().start(new Runnable() { 
  4.                @Override 
  5.                public void run() { 
  6.                    try { 
  7.                        //休眠100ms 
  8.                        Thread.sleep(100); 
  9.                    } catch (InterruptedException e) { 
  10.                        e.printStackTrace(); 
  11.                    } 
  12.                } 
  13.            }); 
  14.        } 
  15.    } 

 

03ThreadPoolExecutor

為了能夠更好地控制多線(xiàn)程,JDK提供了一套Executor框架,幫助開(kāi)發(fā)人員有效地進(jìn)行線(xiàn)程控制。Executor框架無(wú)論是newFixedThreadPool()方法、newSingleThreadExecutor()方法還是newCachedThreadPool()方法,其內(nèi)部實(shí)現(xiàn)均使用了 ThreadPoolExecutor:

  1. public static ExecutorService newCachedThreadPool() { 
  2.         return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 
  3.                                       60L, TimeUnit.SECONDS, 
  4.                                       new SynchronousQueue<Runnable>()); 
  5.     } 
  6.      
  7.     public static ExecutorService newFixedThreadPool(int nThreads) { 
  8.         return new ThreadPoolExecutor(nThreads, nThreads, 
  9.                                       0L, TimeUnit.MILLISECONDS, 
  10.                                       new LinkedBlockingQueue<Runnable>()); 
  11.     } 
  12.      
  13.     public static ExecutorService newSingleThreadExecutor() { 
  14.         return new FinalizableDelegatedExecutorService 
  15.             (new ThreadPoolExecutor(1, 1, 
  16.                                     0L, TimeUnit.MILLISECONDS, 
  17.                                     new LinkedBlockingQueue<Runnable>())); 
  18.     } 

由以上線(xiàn)程池的實(shí)現(xiàn)代碼可以知道,它們只是對(duì) ThreadPoolExecutor 類(lèi)的封裝。為何 ThreadPoolExecutor 類(lèi)有如此強(qiáng)大的功能?來(lái)看一下 ThreadPoolExecutor 最重要的構(gòu)造方法。

3.1 構(gòu)造方法

ThreadPoolExecutor最重要的構(gòu)造方法如下:

  1. public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 

方法參數(shù)如下:

ThreadPoolExecutor的使用示例,通過(guò)execute()方法提交任務(wù)。

  1. public static void main(String[] args) { 
  2.         ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 
  3.         for (int i = 0; i < 10; i++) { 
  4.             executor.execute(new Runnable() { 
  5.                 @Override 
  6.                 public void run() { 
  7.                     System.out.println(Thread.currentThread().getName()); 
  8.                 } 
  9.             }); 
  10.         } 
  11.         executor.shutdown(); 
  12.     } 

或者通過(guò)submit()方法提交任務(wù)

  1. public static void main(String[] args) throws ExecutionException, InterruptedException { 
  2.         ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 
  3.         List<Future> futureList = new Vector<>(); 
  4.         //在其它線(xiàn)程中執(zhí)行100次下列方法 
  5.         for (int i = 0; i < 100; i++) { 
  6.             futureList.add(executor.submit(new Callable<String>() { 
  7.                 @Override 
  8.                 public String call() throws Exception { 
  9.                     return Thread.currentThread().getName(); 
  10.                 } 
  11.             })); 
  12.         } 
  13.         for (int i = 0;i<futureList.size();i++){ 
  14.             Object o = futureList.get(i).get(); 
  15.             System.out.println(o.toString()); 
  16.         } 
  17.         executor.shutdown(); 
  18.     } 

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

  1. ... 
  2. pool-1-thread-4 
  3. pool-1-thread-3 
  4. pool-1-thread-2 

下面主要講解ThreadPoolExecutor的構(gòu)造方法中workQueue和RejectedExecutionHandler參數(shù),其它參數(shù)都很簡(jiǎn)單。

3.2 workQueue任務(wù)隊(duì)列

用于保存等待執(zhí)行的任務(wù)的阻塞隊(duì)列??梢赃x擇以下幾個(gè)阻塞隊(duì)列。

  • ArrayBlockingQueue: 是一個(gè)基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列,按FIFO原則進(jìn)行排序
  • LinkedBlockingQueue: 一個(gè)基于鏈表結(jié)構(gòu)的阻塞隊(duì)列,吞吐量高于A(yíng)rrayBlockingQueue。靜態(tài)工廠(chǎng)方法Excutors.newFixedThreadPool()使用了這個(gè)隊(duì)列
  • SynchronousQueue: 一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。每個(gè)插入操作必須等到另一個(gè)線(xiàn)程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài),吞吐量高于LinkedBlockingQueue,靜態(tài)工廠(chǎng)方法Excutors.newCachedThreadPool()使用了這個(gè)隊(duì)列
  • PriorityBlockingQueue: 一個(gè)具有優(yōu)先級(jí)的***阻塞隊(duì)列。

3.3 RejectedExecutionHandler飽和策略

當(dāng)隊(duì)列和線(xiàn)程池都滿(mǎn)了,說(shuō)明線(xiàn)程池處于飽和狀態(tài),那么必須采取一種策略還處理新提交的任務(wù)。它可以有如下四個(gè)選項(xiàng):

  • AbortPolicy : 直接拋出異常,默認(rèn)情況下采用這種策略
  • CallerRunsPolicy : 只用調(diào)用者所在線(xiàn)程來(lái)運(yùn)行任務(wù)
  • DiscardOldestPolicy : 丟棄隊(duì)列里最近的一個(gè)任務(wù),并執(zhí)行當(dāng)前任務(wù)
  • DiscardPolicy : 不處理,丟棄掉

更多的時(shí)候,我們應(yīng)該通過(guò)實(shí)現(xiàn)RejectedExecutionHandler 接口來(lái)自定義策略,比如記錄日志或持久化存儲(chǔ)等。

3.4 submit()與execute()

可以使用execute和submit兩個(gè)方法向線(xiàn)程池提交任務(wù)。

execute方法用于提交不需要返回值的任務(wù),利用這種方式提交的任務(wù)無(wú)法得知是否正常執(zhí)行

submit方法用于提交一個(gè)任務(wù)并帶有返回值,這個(gè)方法將返回一個(gè)Future類(lèi)型對(duì)象。可以通過(guò)這個(gè)返回對(duì)象判斷任務(wù)是否執(zhí)行成功,并且可以通過(guò)future.get()方法來(lái)獲取返回值,get()方法會(huì)阻塞當(dāng)前線(xiàn)程直到任務(wù)完成。

3.5 shutdown()與shutdownNow()

可以通過(guò)調(diào)用 shutdown() 或 shutdownNow() 方法來(lái)關(guān)閉線(xiàn)程池。它們的原理是遍歷線(xiàn)程池中的工作線(xiàn)程,然后逐個(gè)調(diào)用線(xiàn)程的 interrupt 方法來(lái)中斷線(xiàn)程,所以無(wú)法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無(wú)法停止。

這倆方法的區(qū)別是,shutdownNow() 首先將線(xiàn)程池的狀態(tài)設(shè)置成STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線(xiàn)程,并返回等待執(zhí)行任務(wù)的列表,而 shutdown() 只是將線(xiàn)程池的狀態(tài)設(shè)置成 SHUTDOWN 狀態(tài),然后中斷所有沒(méi)有正在執(zhí)行任務(wù)的線(xiàn)程。

只要調(diào)用了這兩個(gè)關(guān)閉方法的任意一個(gè),isShutdown 方法就會(huì)返回 true。當(dāng)所有的任務(wù)都已關(guān)閉了,才表示線(xiàn)程池關(guān)閉成功,這時(shí)調(diào)用 isTerminaced 方法會(huì)返回 true。

通常調(diào)用 shutdown() 方法來(lái)關(guān)閉線(xiàn)程池,如果任務(wù)不一定要執(zhí)行完,則可以調(diào)用 shutdownNow() 方法。

3.6 合理配置線(xiàn)程池

要想合理地配置線(xiàn)程池,首先要分析任務(wù)特性

  • 任務(wù)的性質(zhì):CPU密集型任務(wù)、IO密集型任務(wù)和混合型任務(wù)。
  • 任務(wù)的優(yōu)先級(jí):高、中和低。
  • 任務(wù)的執(zhí)行時(shí)間:長(zhǎng)、中和短。
  • 任務(wù)的依賴(lài)性:是否依賴(lài)其他系統(tǒng)資源,如數(shù)據(jù)庫(kù)連接。

性質(zhì)不同的任務(wù)可以用不同規(guī)模的線(xiàn)程池分開(kāi)處理。

CPU密集型任務(wù)應(yīng)該配置盡可能少的線(xiàn)程,如配置N+1個(gè)線(xiàn)程,N位CPU的個(gè)數(shù)。

而IO密集型任務(wù)線(xiàn)程并不是一直在執(zhí)行任務(wù),則應(yīng)配置盡可能多的線(xiàn)程,如2*N。

混合型任務(wù),如果可以拆分,將其拆分成一個(gè)CPU密集型任務(wù)和一個(gè)IO密集型任務(wù),只要這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差不是太大,那么分解后執(zhí)行的吞吐量將高于串行執(zhí)行的吞吐量。如果這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差很大,則沒(méi)有必要進(jìn)行分解。可以通過(guò)Runtime.getRuntime().availableProcessors()方法獲得當(dāng)前設(shè)備的CPU個(gè)數(shù)。

優(yōu)先級(jí)不同的任務(wù)可以使用優(yōu)先級(jí)隊(duì)列PriorityBlockingQueue來(lái)處理。它可以讓優(yōu)先級(jí)高的任務(wù)先執(zhí)行。

3.7 線(xiàn)程池的監(jiān)控

由于大量的使用線(xiàn)程池,所以很有必要對(duì)其進(jìn)行監(jiān)控。可以通過(guò)繼承線(xiàn)程池來(lái)自定義線(xiàn)程池,重寫(xiě)線(xiàn)程池的beforeExecute、afterExecute 和 terminated 方法,也可以在任務(wù)執(zhí)行前,執(zhí)行后和線(xiàn)程池關(guān)閉前執(zhí)行一些代碼來(lái)進(jìn)行監(jiān)控。在監(jiān)控線(xiàn)程池的時(shí)候可以使用一下屬性:

(1) taskCount:線(xiàn)程池需要執(zhí)行的任務(wù)數(shù)量

(2) completedTaskCount:線(xiàn)程池在運(yùn)行過(guò)程中已完成的任務(wù)數(shù)量,小于或等于taskCount

(3) largestPoolSize: 線(xiàn)程池里曾經(jīng)創(chuàng)建過(guò)***的線(xiàn)程數(shù)量。通過(guò)這個(gè)數(shù)據(jù)可以知道線(xiàn)程池是否曾經(jīng)滿(mǎn)過(guò)。如該數(shù)值等于線(xiàn)程池***大小,則表示線(xiàn)程池曾經(jīng)滿(mǎn)過(guò)。

(4) getPoolSize:線(xiàn)程池的線(xiàn)程數(shù)量。如果線(xiàn)程池不銷(xiāo)毀的話(huà),線(xiàn)程池里的線(xiàn)程不會(huì)自動(dòng)銷(xiāo)毀,所以這個(gè)大小只增不減。

(5) getActiveCount:獲取活動(dòng)的線(xiàn)程數(shù)

 

04Executor多線(xiàn)程框架

ThreadPoolExecutor 表示一個(gè)線(xiàn)程池,Executors 類(lèi)則扮演著線(xiàn)程池工廠(chǎng)的角色,通過(guò) Executors 可以取得一個(gè)特定功能的線(xiàn)程池。

使用 Executors 框架實(shí)現(xiàn)上節(jié)中的例子,其代碼如下:

  1. public static void main(String[] args) { 
  2.         //新建一個(gè)線(xiàn)程池 
  3.         ExecutorService executor = Executors.newCachedThreadPool(); 
  4.         //在其它線(xiàn)程中執(zhí)行100次下列方法 
  5.         for (int i = 0; i < 100; i++) { 
  6.             executor.execute(new Runnable() { 
  7.                 @Override 
  8.                 public void run() { 
  9.                     System.out.println(Thread.currentThread().getName()); 
  10.                 } 
  11.             }); 
  12.         } 
  13.         //執(zhí)行完關(guān)閉 
  14.         executor.shutdown(); 
  15.     } 

4.1 Executors框架的結(jié)構(gòu)

1.任務(wù)

包括被執(zhí)行任務(wù)需要實(shí)現(xiàn)的接口:Runnable 接口或 Callable 接口。

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

包括任務(wù)執(zhí)行機(jī)制的核心接口 Executor,以及繼承自 Executor 的ExecutorService 接口。Executor框架有兩個(gè)關(guān)鍵類(lèi)實(shí)現(xiàn)了 ExecutorService 接口(ThreadPoolExecutor 和 ScheduledThreadPoolExecutor)。

3.異步計(jì)算的結(jié)果

包括接口 Future 和實(shí)現(xiàn)Future接口的FutureTask類(lèi)。

4.2 Executors工廠(chǎng)方法

Executors工廠(chǎng)類(lèi)的主要方法:

  1. public static ExecutorService newFixedThreadPool(int nThreads)  

該方法返回一個(gè)固定線(xiàn)程數(shù)量的線(xiàn)程池,該線(xiàn)程池中的線(xiàn)程數(shù)量始終不變。當(dāng)有一個(gè)新的任務(wù)提交時(shí),線(xiàn)程池中若有空閑線(xiàn)程,則立即執(zhí)行。若沒(méi)有,則新的任務(wù)會(huì)被暫存在一個(gè)任務(wù)隊(duì)列中,待有線(xiàn)程空閑時(shí),便處理在任務(wù)隊(duì)列中的任務(wù)。

  1. public static ExecutorService newSingleThreadExecutor() 

該方法返回一個(gè)只有一個(gè)線(xiàn)程的線(xiàn)程池。若多余一個(gè)任務(wù)被提交到線(xiàn)程池,任務(wù)會(huì)被保存在一個(gè)任務(wù)隊(duì)列中,待線(xiàn)程空閑,按先入先出的順序執(zhí)行隊(duì)列中的任務(wù)。

  1. public static ExecutorService newCachedThreadPool() 

該方法返回一個(gè)可根據(jù)實(shí)際情況調(diào)整線(xiàn)程數(shù)量的線(xiàn)程池。線(xiàn)程池的線(xiàn)程數(shù)量不確定,但若有空閑線(xiàn)程可以復(fù)用,則會(huì)優(yōu)先使用可復(fù)用的線(xiàn)程。但所有線(xiàn)程均在工作,又有新的任務(wù)提交,則會(huì)創(chuàng)建新的線(xiàn)程處理任務(wù)。所有線(xiàn)程在當(dāng)前任務(wù)執(zhí)行完畢后,將返回線(xiàn)程池進(jìn)行復(fù)用。

  1. public static ScheduledExecutorService newSingleThreadScheduledExecutor()  

該方法返回一個(gè)ScheduledExecutorService對(duì)象,線(xiàn)程池大小為1。ScheduledExecutorService接口在ExecutorService接口之上擴(kuò)展了在給定時(shí)間執(zhí)行某任務(wù)的功能,如在某個(gè)固定的延時(shí)之后執(zhí)行,或者周期性執(zhí)行某個(gè)任務(wù)。

  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 

該方法也返回一個(gè) ScheduledExecutorService 對(duì)象,但該線(xiàn)程池可以指定線(xiàn)程數(shù)量。

4.3 ThreadPoolExecutor與ScheduledThreadPoolExecutor

在前面提到了Executors 類(lèi)扮演著線(xiàn)程池工廠(chǎng)的角色,通過(guò) Executors 可以取得一個(gè)特定功能的線(xiàn)程池。Executors 工廠(chǎng)類(lèi)的主要方法可以創(chuàng)建 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 線(xiàn)程池。

關(guān)于ThreadPoolExecutor ,前面第3節(jié)已經(jīng)詳細(xì)敘述。ScheduledThreadPoolExecutor 也是ExecutorService接口的實(shí)現(xiàn)類(lèi),可以在給定的延遲后運(yùn)行命令,或者定期執(zhí)行命令。ScheduledThreadPoolExecutor 比 Timer 更靈活,功能更強(qiáng)大。

4.4 Future與FutureTask

上面的示例中使用 execute() 方法提交任務(wù),用于提交不需要返回值的任務(wù)。如果我們需要獲取執(zhí)行任務(wù)之后的返回值,可以使用submit()方法。

示例代碼:

  1. public static void main(String[] args) throws InterruptedException, ExecutionException { 
  2.         //新建一個(gè)線(xiàn)程池 
  3.         ExecutorService executor = Executors.newCachedThreadPool(); 
  4.         List<Future> futureList = new Vector<>(); 
  5.         //在其它線(xiàn)程中執(zhí)行100次下列方法 
  6.         for (int i = 0; i < 100; i++) { 
  7.             futureList.add(executor.submit(new Callable<String>() { 
  8.                 @Override 
  9.                 public String call() throws Exception { 
  10.                     return Thread.currentThread().getName()+" "+System.currentTimeMillis()+" "
  11.                 } 
  12.             })); 
  13.         } 
  14.         for (int i = 0;i<futureList.size();i++){ 
  15.             Object o = futureList.get(i).get(); 
  16.             System.out.println(o.toString()+i); 
  17.         } 
  18.         executor.shutdown(); 
  19.     } 

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

  1. ... 
  2. pool-1-thread-11 1537872778612 96 
  3. pool-1-thread-11 1537872778613 97 
  4. pool-1-thread-10 1537872778613 98 
  5. pool-1-thread-10 1537872778613 99 

到這里,就不得不提Future接口與FutureTask實(shí)現(xiàn)類(lèi),它們代表異步計(jì)算的結(jié)果。

  1. Future<T> submit(Callable<T> task) 
  2. Future<?> submit(Runnable task); 
  3. Future<T> submit(Runnable task, T result); 

當(dāng)我們submit()提交后,會(huì)返回一個(gè)Future對(duì)象,到JDK1.8,返回的實(shí)際是FutureTask實(shí)現(xiàn)類(lèi)。submit() 方法支持 Runnable 或 Callable 類(lèi)型的參數(shù)。Runnable 接口 和Callable 接口的區(qū)別就是 Runnable 不會(huì)返回結(jié)果,Callable 會(huì)返回結(jié)果。

主線(xiàn)程可以執(zhí)行 futureTask.get() 方法來(lái)阻塞當(dāng)前線(xiàn)程直到任務(wù)執(zhí)行完成,任務(wù)完成后返回任務(wù)執(zhí)行的結(jié)果。

futureTask.get(long timeout, TimeUnit unit) 方法則會(huì)阻塞當(dāng)前線(xiàn)程一段時(shí)間立即返回,這時(shí)候有可能任務(wù)沒(méi)有執(zhí)行完。

主線(xiàn)程也可以執(zhí)行 futureTask.cancel(boolean mayInterruptIfRunning) 來(lái)取消此任務(wù)的執(zhí)行。

futureTask.isCancelled方法表示任務(wù)是否被取消成功,如果在任務(wù)正常完成前被取消成功,則返回 true。

futureTask.isDone方法表示任務(wù)是否已經(jīng)完成,若任務(wù)完成,則返回true。

責(zé)任編輯:武曉燕 來(lái)源: 程序員柯南
相關(guān)推薦

2020-07-03 08:21:57

Java集合框架

2022-06-20 09:01:23

Git插件項(xiàng)目

2023-02-10 09:04:27

2020-02-18 16:20:03

Redis ANSI C語(yǔ)言日志型

2022-04-07 10:39:21

反射Java安全

2022-08-01 11:33:09

用戶(hù)分析標(biāo)簽策略

2021-04-08 07:37:39

隊(duì)列數(shù)據(jù)結(jié)構(gòu)算法

2023-09-11 08:13:03

分布式跟蹤工具

2019-09-05 08:14:44

Puppet部署結(jié)構(gòu)

2022-04-10 23:21:04

SSH協(xié)議網(wǎng)絡(luò)安全

2020-07-06 08:06:00

Java模塊系統(tǒng)

2019-05-14 09:31:16

架構(gòu)整潔軟件編程范式

2018-05-22 08:24:50

PythonPyMongoMongoDB

2023-10-17 08:15:28

API前后端分離

2024-09-23 08:00:00

消息隊(duì)列MQ分布式系統(tǒng)

2017-03-11 22:19:09

深度學(xué)習(xí)

2023-11-18 09:30:42

模型AI

2022-07-06 12:07:06

Python函數(shù)式編程

2019-04-01 10:43:59

Linux問(wèn)題故障

2022-05-19 08:28:19

索引數(shù)據(jù)庫(kù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)