相關概念
進程是指一個內存中運行的應用程序,每個進程都有自己獨立的一塊內存空間,一個進程中可以啟動多個線程。
一個進程是一個獨立的運行環境,它可以被看作一個程序或者一個應用。而線程是在進程中執行的一個任務。Java運行環境是一個包含了不同的類和程序的單一進程。線程可以被稱為輕量級進程。線程需要較少的資源來創建和駐留在進程中,并且可以共享進程中的資源。
多線程程序中,多個線程被并發的執行以提高程序的效率,CPU
不會因為某個線程需要等待資源而進入空閑狀態。多個線程共享堆內存(heap memory
),因此創建多個線程去執行一些任務會比創建多個進程更好。舉個例子,Servlets
比 CGI
更好,是因為 Servlets
支持多線程而 CGI
不支持。
這里所謂的多個線程“同時”執行是人的感覺,實際上,是多個線程輪換執行。
線程調度器(Thread Scheduler
)是一個操作系統服務,它負責為Runnable
狀態的線程分配CPU
時間。一旦我們創建一個線程并啟動它,它的執行便依賴于線程調度器的實現。
時間片(Time Slicing
)是指將可用的CPU
時間分配給可用的Runnable
線程的過程。分配CPU
時間可以基于線程優先級或者線程等待的時間。線程調度并不受到Java
虛擬機控制,所以由應用程序來控制它是更好的選擇(也就是說不要讓你的程序依賴于線程的優先級)。
線程的生命周期(六種狀態)
public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
}
- NEW:只存在于線程剛創建,未調用
start
之前。
MyThread myThread = new MyThread();System.out.println(myThread.getState());
- RUNNABLE:正在
JVM
中執行,但是這個"執行",不一定是真的在運行, 也有可能是在等待CPU
資源。所以,在網上,有人把這個狀態區分為READY
和RUNNING
兩個,一個表示的start
了,資源一到位隨時可以執行,另一個表示真正的執行中,這取決于操作系統處理器。
MyThread myThread = new MyThread();myThread.start();System.out.println(myThread.getState());
- BLOCKED:線程等待獲取一個鎖,來繼續執行下一步的操作,比較經典的就是
synchronized
關鍵字,這個關鍵字修飾的代碼塊或者方法,均需要獲取到對應的鎖,在未獲取之前,其線程的狀態就一直未BLOCKED
,如果線程長時間處于這種狀態下,我們就要當心是否會出現死鎖的情況。
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {byte[] lock = new byte[0];MyThread thread1 = new MyThread(lock);thread1.start();MyThread thread2 = new MyThread(lock);thread2.start();Thread.sleep(1000);//等一會再檢查狀態System.out.println(thread2.getState());}}class MyThread extends Thread {private byte[] lock = new byte[0];public MyThread(byte[] lock) {this.lock = lock;}@Overridepublic void run() {synchronized (lock) {try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("done");}}
}
-
WAITING:等待狀態。進入這個狀態,一定是執行了如下的一些代碼,例如
Object.wait()
Thread.join()
LockSupport.park()
當一個線程執行了
Object.wait()
的時候,它一定在等待另一個線程執行Object.notify()
或者Object.notifyAll()
。或者一個線程thread
,其在主線程中被執行了thread.join()
的時候,主線程即會等待該線程執行完成。當一個線程執行了LockSupport.park()
的時候,其在等待執行LockSupport.unpark(thread)
。當該線程處于這種等待的時候,其狀態即為WAITING
。需要關注的是,這邊的等待是沒有時間限制的,當發現有這種狀態的線程的時候,若其長時間處于這種狀態,也需要關注下程序內部有無邏輯異常。LockSupport.park()
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {byte[] lock = new byte[0];MyThread thread1 = new MyThread(lock);thread1.start();Thread.sleep(100);System.out.println(thread1.getState());LockSupport.unpark(thread1);Thread.sleep(100);System.out.println(thread1.getState());}}class MyThread extends Thread {private byte[] lock = new byte[0];public MyThread(byte[] lock) {this.lock = lock;}@Overridepublic void run() {LockSupport.park();} }
Object.wait()
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {byte[] lock = new byte[0];MyThread thread1 = new MyThread(lock);thread1.start();Thread.sleep(100);System.out.println(thread1.getState()); //這時候線程狀態應為WAITINGsynchronized (lock){lock.notify(); //notify通知wait的線程}Thread.sleep(100);System.out.println(thread1.getState());}}class MyThread extends Thread {private byte[] lock = new byte[0];public MyThread(byte[] lock) {this.lock = lock;}@Overridepublic void run() {synchronized (lock){try {lock.wait(); //wait并允許其他線程同步lock} catch (InterruptedException e) {e.printStackTrace();}}} }
Thread.join()
public class MyThreadTest {public static void main(String[] args) throws InterruptedException {byte[] lock = new byte[0];MyThread1 thread1 = new MyThread1(lock);thread1.start();MyThread2 thread2 = new MyThread2(thread1);thread2.start();Thread.sleep(100);System.out.println(thread2.getState());}}class MyThread1 extends Thread {private byte[] lock = new byte[0];public MyThread1(byte[] lock) {this.lock = lock;}@Overridepublic void run() {try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}} }class MyThread2 extends Thread {Thread thread;public MyThread2(Thread thread) {this.thread = thread;}@Overridepublic void run() {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}} }
-
TIMED_WAITING:這個狀態和
WAITING
狀態的區別就是,這個狀態的等待是有一定時效的,即可以理解為WAITING
狀態等待的時間是永久的,即必須等到某個條件符合才能繼續往下走,否則線程不會被喚醒。但是TIMED_WAITING
,等待一段時間之后,會喚醒線程去重新獲取鎖。當執行如下代碼的時候,對應的線程會進入到TIMED_WAITING
狀態。- Thread.sleep(long)
- Object.wait(long)
- Thread.join(long)
- LockSupport.parkNanos()
- LockSupport.parkUntil()
-
TERMINATED:這個狀態很好理解,即為線程執行結束之后的狀態
線程的狀態圖
?