1. 簡述線程,程序、進程的基本概念。以及他們之間關系是什么?
線程與進程相似,但線程是一個比進程更小的執行單位。一個進程在其執行的過程中可以產生多個線程。與進程不同的是同類的多個線程共享同一塊內存空間和一組系統資源,所以系統在產生一個線程,或是在各個線程之間作切換工作時,負擔要比進程小得多,也正因為如此,線程也被稱為輕量級進程。
程序是含有指令和數據的文件,被存儲在磁盤或其他的數據存儲設備中,也就是說程序是靜態的代碼。
進程是程序的一次執行過程,是系統運行程序的基本單位,因此進程是動態的。系統運行一個程序即是一個進程從創建,運行到消亡的過程。簡單來說,一個進程就是一個執行中的程序,它在計算機中一個指令接着一個指令地執行着,同時,每個進程還占有某些系統資源如CPU時間,內存空間,文件,文件,輸入輸出設備的使用權等等。換句話說,當程序在執行時,將會被操作系統載入內存中。
線程 是 進程 划分成的更小的運行單位。線程和進程最大的不同在於基本上各進程是獨立的,而各線程則不一定,因為同一進程中的線程極有可能會相互影響。從另一角度來說,進程屬於操作系統的范疇,主要是同一段時間內,可以同時執行一個以上的程序,而線程則是在同一程序內幾乎同時執行一個以上的程序段。
線程上下文的切換比進程上下文切換要快很多
-
進程切換時,涉及到當前進程的CPU環境的保存和新被調度運行進程的CPU環境的設置。
-
線程切換僅需要保存和設置少量的寄存器內容,不涉及存儲管理方面的操作。
2. 線程有哪些基本狀態?這些狀態是如何定義的?
-
新建(new):新創建了一個線程對象。
-
可運行(runnable):線程對象創建后,其他線程(比如main線程)調用了該對象的start()方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲 取cpu的使用權。
-
運行(running):可運行狀態(runnable)的線程獲得了cpu時間片(timeslice),執行程序代碼。
-
阻塞(block):阻塞狀態是指線程因為某種原因放棄了cpu使用權,也即讓出了cpu timeslice,暫時停止運行。直到線程進入可運行(runnable)狀態,才有 機會再次獲得cpu timeslice轉到運行(running)狀態。阻塞的情況分三種:
-
(一). 等待阻塞:運行(running)的線程執行o.wait()方法,JVM會把該線程放 入等待隊列(waiting queue)中。
-
(二). 同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步 鎖 被別的線程占用,則JVM會把該線程放入鎖池(lock pool)中。
-
(三). 其他阻塞: 運行(running)的線程執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入可運行(runnable)狀態。
-
5.死亡(dead):線程run()、main()方法執行結束,或者因異常退出了run() 方法,則該線程結束生命周期。死亡的線程不可再次復生。

- 還沒起床:sleeping
- 起床收拾好了,隨時可以坐地鐵出發:Runnable
- 等地鐵來:Waiting
- 地鐵來了,但要排隊上地鐵:I/O阻塞
- 上了地鐵,發現暫時沒座位:synchronized阻塞
- 地鐵上找到座位:Running
- 到達目的地:Dead
- 使用線程可以把占據長時間的程序中的任務放到后台去處理。
- 用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度。
- 程序的運行速度可能加快。
public class MyThread extends Thread { @Override public void run() { super.run(); System.out.println("MyThread"); } }
Run.java
public class Run { public static void main(String[] args) { MyThread mythread = new MyThread(); mythread.start(); System.out.println("運行結束"); } }
運行結果: 
從上面的運行結果可以看出:線程是一個子任務,CPU以不確定的方式,或者說是以隨機的時間來調用線程中的run方法。
③使用線程池
在《阿里巴巴Java開發手冊》“並發處理”這一章節,明確指出線程資源必須通過線程池提供,不允許在應用中自行顯示創建線程。
為什么呢?
使用線程池的好處是減少在創建和銷毀線程上所消耗的時間以及系統資源開銷,解決資源不足的問題。如果不使用線程池,有可能會造成系統創建大量同類線程而導致消耗完內存或者“過度切換”的問題。
另外《阿里巴巴Java開發手冊》中強制線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險
- FixedThreadPool 和 SingleThreadExecutor : 允許請求的隊列長度為 Integer.MAX_VALUE,可能堆積大量的請求,從而導致OOM。
- CachedThreadPool 和 ScheduledThreadPool : 允許創建的線程數量為 Integer.MAX_VALUE ,可能會創建大量線程,從而導致OOM。
6 線程的優先級
用戶線程
守護線程
-
特點: 一旦所有用戶線程都結束運行,守護線程會隨JVM一起結束工作
-
應用: 數據庫連接池中的檢測線程,JVM虛擬機啟動后的檢測線程
-
最常見的守護線程: 垃圾回收線程
- 兩者最主要的區別在於:sleep方法沒有釋放鎖,而wait方法釋放了鎖 。
- 兩者都可以暫停線程的執行。
- Wait通常被用於線程間交互/通信,sleep通常被用於暫停執行。
- wait()方法被調用后,線程不會自動蘇醒,需要別的線程調用同一個對象上的notify()或者notifyAll()方法。sleep()方法執行完成后,線程會自動蘇醒。
