亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

Java ThreadPool的使用解析

瀏覽:4日期:2022-08-22 11:56:42

簡介

在java中,除了單個使用Thread之外,我們還會使用到ThreadPool來構建線程池,那么在使用線程池的過程中需要注意哪些事情呢?

一起來看看吧。

java自帶的線程池

java提供了一個非常好用的工具類Executors,通過Executors我們可以非常方便的創建出一系列的線程池:

Executors.newCachedThreadPool,根據需要可以創建新線程的線程池。線程池中曾經創建的線程,在完成某個任務后也許會被用來完成另外一項任務。

Executors.newFixedThreadPool(int nThreads) ,創建一個可重用固定線程數的線程池。這個線程池里最多包含nThread個線程。

Executors.newSingleThreadExecutor() ,創建一個使用單個 worker 線程的 Executor。即使任務再多,也只用1個線程完成任務。

Executors.newSingleThreadScheduledExecutor() ,創建一個單線程執行程序,它可安排在給定延遲后運行命令或者定期執行。

提交給線程池的線程要是可以被中斷的

ExecutorService線程池提供了兩個很方便的停止線程池中線程的方法,他們是shutdown和shutdownNow。

shutdown不會接受新的任務,但是會等待現有任務執行完畢。而shutdownNow會嘗試立馬終止現有運行的線程。

那么它是怎么實現的呢?我們看一個ThreadPoolExecutor中的一個實現:

public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); advanceRunState(STOP); interruptWorkers(); tasks = drainQueue(); } finally { mainLock.unlock(); } tryTerminate(); return tasks; }

里面有一個interruptWorkers()方法的調用,實際上就是去中斷當前運行的線程。

所以我們可以得到一個結論,提交到ExecutorService中的任務一定要是可以被中斷的,否則shutdownNow方法將會失效。

先看一個錯誤的使用例子:

public void wrongSubmit(){ Runnable runnable= ()->{ try(SocketChannel sc = SocketChannel.open(new InetSocketAddress('127.0.0.1', 8080))) { ByteBuffer buf = ByteBuffer.allocate(1024); while(true){sc.read(buf); } } catch (IOException e) {e.printStackTrace(); } }; ExecutorService pool = Executors.newFixedThreadPool(10); pool.submit(runnable); pool.shutdownNow(); }

在這個例子中,運行的代碼無法處理中斷,所以將會一直運行。

下面看下正確的寫法:

public void correctSubmit(){ Runnable runnable= ()->{ try(SocketChannel sc = SocketChannel.open(new InetSocketAddress('127.0.0.1', 8080))) {ByteBuffer buf = ByteBuffer.allocate(1024);while(!Thread.interrupted()){ sc.read(buf);} } catch (IOException e) {e.printStackTrace(); } }; ExecutorService pool = Executors.newFixedThreadPool(10); pool.submit(runnable); pool.shutdownNow(); }

我們需要在while循環中加上中斷的判斷,從而控制程序的執行。

正確處理線程池中線程的異常

如果在線程池中的線程發生了異常,比如RuntimeException,我們怎么才能夠捕捉到呢? 如果不能夠對異常進行合理的處理,那么將會產生不可預料的問題。

看下面的例子:

public void wrongSubmit() throws InterruptedException { ExecutorService pool = Executors.newFixedThreadPool(10); Runnable runnable= ()->{ throw new NullPointerException(); }; pool.execute(runnable); Thread.sleep(5000); System.out.println('finished!'); }

上面的例子中,我們submit了一個任務,在任務中會拋出一個NullPointerException,因為是非checked異常,所以不需要顯式捕獲,在任務運行完畢之后,我們基本上是不能夠得知任務是否運行成功了。

那么,怎么才能夠捕獲這樣的線程池異常呢?這里介紹大家幾個方法。

第一種方法就是繼承ThreadPoolExecutor,重寫

protected void afterExecute(Runnable r, Throwable t) { }

protected void terminated() { }

這兩個方法。

其中afterExecute會在任務執行完畢之后被調用,Throwable t中保存的是可能出現的運行時異常和Error。我們可以根據需要進行處理。

而terminated是在線程池中所有的任務都被調用完畢之后才被調用的。我們可以在其中做一些資源的清理工作。

第二種方法就是使用UncaughtExceptionHandler。

Thread類中提供了一個setUncaughtExceptionHandler方法,用來處理捕獲的異常,我們可以在創建Thread的時候,為其添加一個UncaughtExceptionHandler就可以了。

但是ExecutorService執行的是一個個的Runnable,怎么使用ExecutorService來提交Thread呢?

別怕, Executors在構建線程池的時候,還可以讓我們傳入ThreadFactory,從而構建自定義的Thread。

public void useExceptionHandler() throws InterruptedException { ThreadFactory factory =new ExceptionThreadFactory(new MyExceptionHandler()); ExecutorService pool =Executors.newFixedThreadPool(10, factory); Runnable runnable= ()->{ throw new NullPointerException(); }; pool.execute(runnable); Thread.sleep(5000); System.out.println('finished!'); } public static class ExceptionThreadFactory implements ThreadFactory { private static final ThreadFactory defaultFactory =Executors.defaultThreadFactory(); private final Thread.UncaughtExceptionHandler handler; public ExceptionThreadFactory(Thread.UncaughtExceptionHandler handler) { this.handler = handler; } @Override public Thread newThread(Runnable run) { Thread thread = defaultFactory.newThread(run); thread.setUncaughtExceptionHandler(handler); return thread; } } public static class MyExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { } }

上面的例子有點復雜了, 有沒有更簡單點的做法呢?

有的。ExecutorService除了execute來提交任務之外,還可以使用submit來提交任務。不同之處是submit會返回一個Future來保存執行的結果。

public void useFuture() throws InterruptedException { ExecutorService pool = Executors.newFixedThreadPool(10); Runnable runnable= ()->{ throw new NullPointerException(); }; Future future = pool.submit(runnable); try { future.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } Thread.sleep(5000); System.out.println('finished!'); }

當我們在調用future.get()來獲取結果的時候,異常也會被封裝到ExecutionException,我們可以直接獲取到。

線程池中使用ThreadLocal一定要注意清理

我們知道ThreadLocal是Thread中的本地變量,如果我們在線程的運行過程中用到了ThreadLocal,那么當線程被回收之后再次執行其他的任務的時候就會讀取到之前被設置的變量,從而產生未知的問題。

正確的使用方法就是在線程每次執行完任務之后,都去調用一下ThreadLocal的remove操作。

或者在自定義ThreadPoolExecutor中,重寫beforeExecute(Thread t, Runnable r)方法,在其中加入ThreadLocal的remove操作。

本文的代碼:

https://github.com/ddean2009/learn-java-base-9-to-20/tree/master/security

以上就是Java ThreadPool的使用解析的詳細內容,更多關于Java ThreadPool的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 久久er国产精品免费观看1 | 色婷婷六月丁香七月婷婷 | 国产精品成人第一区 | 国产二区三区毛片 | 日本一级特黄大一片免 | 国产欧美一区二区精品性色 | 一级毛片免费不卡 | 噜噜噜天天躁狠狠躁夜夜精品 | 国产a级特黄的片子视频 | 免费看人做人爱视频拍拍拍 | 欧美日韩亚洲二区在线 | 免费一级生活片 | 色屁屁影院 | 99精品视频一区在线视频免费观看 | 欧美三级短视频 | 国语性猛交xxxx乱大交 | 久久99精品久久久久久三级 | 13一14周岁毛片免费 | 视频一区二区在线播放 | 成人免费在线播放视频 | 永久免费的啪啪免费的网址 | 国产性tv国产精品 | 国产精品999 | 国产亚洲人成网站观看 | 激情毛片 | 手机看片日韩高清国产欧美 | 精品一区二区三区视频在线观看免 | 亚洲欧美一区二区三区麻豆 | 草草影院一级毛片a级 | 视频偷拍一级视频在线观看 | 亚洲国产精品成人精品软件 | 亚洲成在人线影视天堂网 | 麻豆传媒视频网站 | 亚洲国产成人私人影院 | 免费观看黄的小视频 | 巨大巨粗巨长 黑人长吊视频 | 一及黄色片 | 免费看黄在线网站 | 看最刺激的欧美毛片 | 91av国产视频 | 一级一级一级毛片免费毛片 |