最近精讀Netty源碼,讀到NioEventLoop部分的時候,發現對Java線程&線程池有些概念還有困惑, 因此深刻總結一下
Java線程池一:線程基礎
Java線程池二:線程池原理html
Java線程建立主要有三種方式:繼承Thread類、實現Runable接口、實現Callable接口java
只有經過調用Thread.start()
方法纔會真正建立一個線程, 調用Thread.run()
並不會多線程
當調用線程關心任務執行結果時,咱們應選擇實現Callable接口的方式建立線程異步
繼承方式實現建立線程ide
@Test public void testCreate_1() { Thread t = new Thread() { @Override public void run() { System.out.println(Thread.currentThread().getName()); throw new RuntimeException(); } }; t.start(); t.run(); }
實現Runnable接口的方式建立線程,這種方式調用線程沒法感知任務線程執行結果(是否執行、成功或者異常)oop
@Test public void testCreate_2() { Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName())); t.start(); }
實現Callable接口,調用線程經過FutureTask對象獲取執行結果(返回值或者異常)線程
@Test public void testCreate_3() throws ExecutionException, InterruptedException { FutureTask<Integer> task = new FutureTask<>(() -> { throw new RuntimeException(); }); new Thread(task).start(); System.out.println(task.get()); }
咱們知道Java線程是使用系統內核線程實現, 因此先來簡單回顧下系統內核線程的狀態code
只有待獲取監視器鎖時纔是阻塞狀態,獲取Java語言實現的鎖(ReentrantLock等)是等待狀態。兩者的區別在於監視器鎖的實現依賴內核變量。htm
假設一段業務邏輯沒有考慮運行時異常, 而運行時異常又恰好發生了,那麼對應的線程就會直接崩潰。因此多線程環境下爲了讓程序更加健壯穩定, 咱們須要捕獲異常。對象
將整個業務邏輯加上異常捕獲(固然代碼就不是很優雅)
@Test public void testExceptionHandle_1() { new Thread(() -> { try { //business code int a = 1, b = 0; a = a / b; } catch (Throwable th) { //log } }).start(); }
使用FutureTask異步回掉處理異常(更加優雅,業務邏輯和異常處理邏輯分離)
@Test public void testExceptionHandle_2() { //業務邏輯 FutureTask<Integer> ft = new FutureTask<>(() -> { //business code int a = 1, b = 0; a = a / b; return a; }); Thread t = new Thread(() -> { ft.run(); handleResult(ft); }); t.start(); } //異常處理邏輯 private void handleResult(FutureTask<Integer> ft) { try { System.out.println("the result is " + ft.get()); } catch (InterruptedException e) { //log or ... e.printStackTrace(); } catch (ExecutionException e) { //log or ... e.printStackTrace(); } }
Java中斷是一種線程間通訊手段。好比A線程給B線程發送一箇中斷信號,B線程收到這個信號,能夠處理也能夠不處理。
void thread.interrupt();//實例方法-中斷線程(線程的中斷標識位置爲1) boolean thread.isInterrupted();//線程是否中斷 & 不清除中斷標識 static boolean Thread.interrupted();//當前線程是否中斷 & 清除中斷標識
實例
線程t_1每次循環會判斷當前線程的中斷狀態,若是當前線程已經被中斷(中斷標識位爲1)就直接返回;
整個通訊過程:主線程把t_1線程的中斷標識位置爲1,t_1獲取到中斷標識位爲1, 而後結束循環。
@Test public void testInterrupt() throws InterruptedException { Thread t_1 = new Thread(() -> { int i = 0; while (true) { boolean isInterrupt = Thread.interrupted(); if (isInterrupt) { System.out.println("i am interrupt, return"); return; } //business code if (i++ % 10000 == 0) { System.out.println(i); } } }); t_1.start(); for (int i = 0; i < 100000; i++) { ; } t_1.interrupt(); }
守護線程
當JVM中的全部的用戶線程都退出後守護線程也會退出
優先級
線程的優先級越高,越有可能更快的執行或者得到更多的可執行時間單元。可是Java線程的優先級只是參考,依賴於具體的實現
thread.join()
調用線程進入WAITING狀態,直到thread線程終止
thread.yield()
當前線程讓出cpu資源,仍處於RUNNABLE狀態