線程狀態
Java的Thread類中對線程的狀態有如下定義:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
NEW
Thread state for a thread which has not yet started.
尚未啓動的線程的線程狀態。
此時線程剛剛創建,並未調用start()方法啓動。
Thread thread = new Thread();
System.out.println(thread.getState()); // NEW
RUNNABLE
Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.
可運行線程的線程狀態。 處於可運行狀態的線程正在Java虛擬機中執行,但它可能正在等待來自操作系統的其他資源,例如處理器。
線程調用start()方法開始運行,這個狀態下也會發生一些等待,一般等待的是其他系統資源,而不是鎖、sleep等。
Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getState())); // RUNNABLE
thread.start();
BLOCKED
Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}.
線程的線程狀態被阻塞等待監視器鎖定。 處於阻塞狀態的線程正在等待監視器鎖定以在調用{@link Object#wait()Object.wait}之後輸入同步塊/方法或重新輸入同步塊/方法。
這種狀態是在有多個線程有同步操作的場景,如下thread1雖然釋放了CPU,但是沒有釋放people的鎖,致使thread2進入了阻塞狀態。
Thread thread1 = new Thread(() -> {
synchronized (people) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
Thread thread2 = new Thread(() -> {
synchronized (people) {
}
});
thread2.start();
WAITING
Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:
{@link Object#wait() Object.wait} with no timeout
{@link #join() Thread.join} with no timeout
{@link LockSupport#park() LockSupport.park}
A thread in the waiting state is waiting for another thread to perform a particular action.
For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.
等待線程的線程狀態。 由於調用以下方法之一,線程處於等待狀態:
Object.wait()
Thread.join()
LockSupport.park()
處於等待狀態的線程正在等待另一個線程執行特定操作。
例如,在對象上調用Object.wait()的線程正在等待另一個線程調用 Object.notify()或Object.notifyAll()。 調用Thread.join()的線程正在等待指定的線程終止。
該狀態下的線程處於等待狀態,當另一線程喚醒這個線程時,線程立馬進入就緒狀態。
Thread thread1 = new Thread(() -> {
synchronized (people) {
try {
people.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
TIMED_WAITING
Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
{@link #sleep Thread.sleep}
{@link Object#wait(long) Object.wait} with timeout
{@link #join(long) Thread.join} with timeout
{@link LockSupport#parkNanos LockSupport.parkNanos}
{@link LockSupport#parkUntil LockSupport.parkUntil}
具有指定等待時間的等待線程的線程狀態。 由於在指定的正等待時間內調用以下方法之一,線程處於定時等待狀態:
Thread.sleep
Object.wait(long)
Thread.join(long)
LockSupport.parkNanos
LockSupport.parkUtil
該狀態的線程需要等待一些時間才能繼續運行。WAITING狀態是當發生某個事情纔會進入就緒狀態,TIMED_WAITING狀態是當時間到達就會進入就緒狀態。
Thread thread1 = new Thread(() -> {
synchronized (people) {
try {
people.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
TERMINATED
Thread state for a terminated thread. The thread has completed execution.
終止線程的線程狀態。 線程已完成執行。
run()方法執行結束後,線程進入TERMINATED狀態。
主要方法
wait()
wait()方法是Object的方法,是在資源的角度阻塞線程,也就是讓線程放棄對資源的佔用。
public static void main(String[] args) {
People people = new People();
// 線程一拿到對象的鎖
Thread thread1 = new Thread(() -> {
synchronized (people) {
System.out.println(1);
try {
// 對象調用wait方法使線程進入WAITING狀態
// people的鎖被釋放
people.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(2);
}
});
thread1.start();
// 線程二運行,拿到對象的鎖
Thread thread2 = new Thread(() -> {
synchronized (people) {
System.out.println(3);
}
});
thread2.start();
}
運行結果:
1
3
因爲線程一依舊處於阻塞狀態,所以主線程main此時並沒有結束運行。
sleep()
sleep()方法是線程的方法,是在線程的角度阻塞線程,無法操作對象鎖,所以如果線程阻塞時鎖住了某個對象,那麼這個對象的鎖將不會被釋放。
public static void main(String[] args) {
People people = new People();
Thread thread1 = new Thread(() -> {
synchronized (people) {
System.out.println(1);
try {
// 線程調用sleep方法阻塞線程,線程進入TIMED_WAITING
// 對象的鎖沒有被釋放
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(2);
}
});
thread1.start();
// 線程二拿不到people的鎖所以不能執行進入就緒狀態
Thread thread2 = new Thread(() -> {
synchronized (people) {
System.out.println(3);
}
});
thread2.start();
}
運行結果:
1
2
3
兩者的區別:
sleep() | wait() | |
---|---|---|
所屬類不同 | Thread類的方法 | Object類的方法 |
時間不同 | 必須指定時間 | 可指定也可不指定時間 |
釋放鎖不同 | 釋放CPU執行權不釋放鎖 | 釋放CPU執行權釋放鎖 |
使用範圍不同 | 可以在任意地方使用 | 只能在同步代碼中使用 |
notify()
notify()和notifyAll()方法喚醒被wait()方法置於WAITING狀態的線程。notify()方法喚醒一個等待資源的線程,如果有多個線程同時等待一個資源,則由JVM選擇一個線程喚醒,使其進入就緒狀態,重新競爭鎖。
public static void main(String[] args) {
People people = new People();
Thread thread1 = new Thread(() -> {
synchronized (people) {
try {
System.out.println(1);
// thread1進入WAITING狀態
// 釋放鎖
people.wait();
System.out.println(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
Thread thread2 = new Thread(() -> {
synchronized (people) {
try {
System.out.println(3);
people.wait();
System.out.println(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread2.start();
Thread thread3 = new Thread(() -> {
synchronized (people) {
System.out.println(5);
// 喚醒一個等待people鎖的線程
people.notify();
System.out.println(6);
}
});
thread3.start();
}
運行結果如下,thread2被喚醒,thread1依舊處於WAITING狀態。
1
3
5
6
4
notifyAll()
notifyAll()方法喚醒所有等待資源的線程。
public static void main(String[] args) {
People people = new People();
Thread thread1 = new Thread(() -> {
synchronized (people) {
try {
System.out.println(1);
people.wait();
System.out.println(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
Thread thread2 = new Thread(() -> {
synchronized (people) {
try {
System.out.println(3);
people.wait();
System.out.println(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread2.start();
Thread thread3 = new Thread(() -> {
synchronized (people) {
System.out.println(5);
// 喚醒所有等待people鎖的線程
people.notifyAll();
System.out.println(6);
}
});
thread3.start();
}
運行結果如下,thread1和thread2均被喚醒。
1
3
5
6
4
2
yield()
yield()方法把CPU讓給同等優先級或更高優先級的線程。注意,其他線程不會立馬進入運行狀態,只是給其他線程提供競爭的機會。
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
System.out.println(1);
Thread.yield();
System.out.println(2);
});
thread1.setPriority(Thread.MIN_PRIORITY);
thread1.start();
Thread thread2 = new Thread(() -> System.out.println(3));
thread2.setPriority(Thread.MAX_PRIORITY);
thread2.start();
}
運行結果:
1
2
3
或
1
3
2
thread1禮讓之後,thread1和thread2一起參與競爭,都有可能進入運行狀態。疑惑?此處thread2的優先級已被設爲最高了,爲什麼不一定是thread2先運行呢?
join()
join()方法會使當前線程等待調用join()方法的線程結束後才能繼續執行。
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(10000);
System.out.println("我剛睡醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
Thread thread2 = new Thread(() -> {
try {
System.out.println(1);
thread1.join();
System.out.println(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread2.start();
}
運行結果:
1
我剛睡醒
2