參考資料:https://redspider.gitbook.io/concurrent/
進程和線程的區別
進程是一個獨立的運行環境,而線程是在進程中執行的一個任務。他們兩個本質的區別是是否單獨占有內存地址空間及其它系統資源(比如I/O):
-
進程單獨占有一定的內存地址空間,所以進程間存在內存隔離,數據是分開的,數據共享復雜但是同步簡單,各個進程之間互不干擾;而線程共享所屬進程占有的內存地址空間和資源,數據共享簡單,但是同步復雜。
-
進程單獨占有一定的內存地址空間,一個進程出現問題不會影響其他進程,不影響主程序的穩定性,可靠性高;一個線程崩潰可能影響整個程序的穩定性,可靠性較低。
-
進程單獨占有一定的內存地址空間,進程的創建和銷毀不僅需要保存寄存器和棧信息,還需要資源的分配回收以及頁調度,開銷較大;線程只需要保存寄存器和棧信息,開銷較小。
線程組(ThreadGroup)
每個Thread必然存在於一個ThreadGroup中,Thread不能獨立於ThreadGroup存在。執行main()方法線程的名字是main,如果在new Thread時沒有顯式指定,那么默認將父線程(當前執行new Thread的線程)線程組設置為自己的線程組。
Start和run的區別
Start()會創建一個新的子線程並啟動
Run()只是Thread的一個普通方法的調用
Thread和Runnable關系
Thread是實現了Runnable接口的類,使得run支持多線程
因類的單一繼承原則,推薦多使用Runnable接口
1 public static void main(String[] args) { 2 3 new Thread(new Runnable() { 4 public void run() { 5 System.out.println("Runnable running.."); 6 } 7 }) { 8 public void run() { 9 System.out.println("Thread running.."); 10 }; 11 }.start(); 12 }
輸出結果為
Thread running..
繼承Thread類,那么在調用start的方法時會去調用Thread的子類的方法
如何給run()方法傳參
構造函數傳參
成員變量傳參
回調函數傳參
如何實現處理線程的返回值
主線程等待法(新建一個屬性來存返回值,當這個屬性還沒值的時候,就等待,直到它有值)
使用Thread類的join()阻塞當前線程以等待子線程處理完畢
通過Callable接口實現,通過FutureTask 或線程池獲取(推薦)
Sleep和wait區別
Sleep是Thread類的方法,wait是Object類的方法
Sleep方法可以在任何地方使用
Wait方法只能在synchronized方法或synchronized塊中使用
Thread.sleep只會讓出CPU,不會導致鎖行為的改變
Object.wait不僅讓出CPU,還會釋放已經占有的同步資源鎖

1 public class ThreadTest { 2 public static void main(String[] args) { 3 final Object lock = new Object(); 4 new Thread(new Runnable() { 5 @Override 6 public void run() { 7 System.out.println("A is waiting to get lock"); 8 synchronized (lock) { 9 try { 10 System.out.println("A get lock"); 11 Thread.sleep(20); 12 System.out.println("A get do wait method"); 13 Thread.sleep(1000);//只會讓出CPU,不會導致鎖行為的改變 14 System.out.println("A is done"); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 }).start();; 21 try { 22 Thread.sleep(10);// 讓A先執行 23 } catch (InterruptedException e1) { 24 e1.printStackTrace(); 25 } 26 new Thread(new Runnable() { 27 @Override 28 public void run() { 29 System.out.println("B is waiting to get lock"); 30 synchronized (lock) { 31 try { 32 System.out.println("B get lock"); 33 System.out.println("B is sleeping 10 ms"); 34 lock.wait(10);//不僅讓出CPU,還會釋放已經占有的同步資源鎖 35 System.out.println("B is done"); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 } 40 } 41 }).start();; 42 } 43 }
等待池
假設線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖,同時線程A就進入到了該對象的等待池中,進入到等待池中的線程不會去競爭該對象的鎖
Notify和notifyAll區別
notifyAll會讓所有處於等待池的線程全部進入鎖池去競爭獲取鎖的機會
notify只會隨機選取一個處於等待池中的線程進入鎖池去競爭獲取鎖的機會
yield
當調用Thread.yield()函數時,會給線程調度器一個當前線程願意讓出CPU使用的暗示,但是線程調度器可能會忽略這個暗示
Interrupt
如果線程處於被阻塞狀態,那么線程將立即退出被阻塞狀態,並拋出一個InterruptedException異常。
如果線程處於正常活動狀態,那么會將該線程的中斷標志設為true,被設置中斷標志的線程將繼續正常運行,不收影響。