1. 線程狀態(tài)
public enum State {
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED;
}
說明:
| 狀態(tài) | 描述 |
|---|---|
NEW |
至今尚未啟動的線程的狀態(tài) |
RUNNABLE |
可運行線程的線程狀態(tài) |
BLOCKED |
受阻塞并且正在等待監(jiān)視器鎖的某一線程的線程狀態(tài) |
WAITING |
某一等待線程的線程狀態(tài) |
TIMED_WAITING |
具有指定等待時間的某一等待線程的線程狀態(tài) |
TERMINATED |
已終止線程的線程狀態(tài)。線程已經(jīng)結(jié)束執(zhí)行 |
如圖:

2. 主要屬性
/*
* 線程名字,通過構(gòu)造參數(shù)來指定
*/
private volatile String name;
/*
* 表示線程的優(yōu)先級,優(yōu)先級越高,越優(yōu)先被執(zhí)行(最大值為10,最小值為1,默認值為5)
*/
private int priority;
/*
* 線程是否是守護線程:當所有非守護進程結(jié)束或死亡后,程序?qū)⑼V? */
private boolean daemon = false;
/*
* 將要執(zhí)行的任務(wù)
*/
private Runnable target;
/*
* 線程組表示一個線程的集合。此外,線程組也可以包含其他線程組。線程組構(gòu)成一棵樹,在樹中,除了初始線程組外,每個線程組都有一個父線程組。
*/
private ThreadGroup group;
/*
* Thread ID
*/
private long tid;
/*
* 用來生成Thread ID使用
*/
private static long threadSeqNumber;
/*
* 第幾個線程,在init初始化線程的時候用來賦給thread.name
*/
private static int threadInitNumber
/*
* 線程從創(chuàng)建到最終的消亡,要經(jīng)歷若干個狀態(tài)。
* 一般來說,線程包括以下這幾個狀態(tài):創(chuàng)建(new)、就緒(runnable)、運行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)
*/
private volatile int threadStatus = 0;
3. 構(gòu)造函數(shù)
源碼
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
構(gòu)造函數(shù)中第三個參數(shù)為線程名稱,而"Thread-" + nextThreadNum()是系統(tǒng)默認的線程名,會將屬性中的threadInitNumber加一。
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
4. 啟動線程
4.1 start()方法
源碼
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0){// 如果狀態(tài)不是`NEW`
throw new IllegalThreadStateException();
}
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
4.2 run方法
源碼
public void run() {
if (target != null) {
target.run();
}
}
5. 守護線程與非守護線程(用戶線程)
守護線程與普通線程的唯一區(qū)別是:
任何一個守護線程都是整個JVM中所有非守護線程的保姆
守護線程與main同生共死,當main退出,它將終止,而普通線程是在任務(wù)執(zhí)行結(jié)束才停止。
Java虛擬機在它所有非守護線程已經(jīng)離開后自動離開。守護線程則是用來服務(wù)用戶線程的,如果沒有其他用戶線程在運行,那么就沒有可服務(wù)對象,也就沒有理由繼續(xù)下去。
示例
public class ThreadDemo extends Thread {
public void run() {
while (true) {
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Thread daemonThread = new Thread(new ThreadDemo());
daemonThread.setName("測試thread");
// 設(shè)置為守護進程
daemonThread.setDaemon(true);
daemonThread.start();
System.out.println("isDaemon = " + daemonThread.isDaemon());
Thread t = new Thread(new ThreadDemo());// 為非守護線程
t.start();
}
}
因為有線程t 的存在,守護線程daemonThread 一直執(zhí)行。
public static void main(String[] args) {
Thread daemonThread = new Thread(new ThreadDemo());
daemonThread.setName("測試thread");
// 設(shè)置為守護進程
daemonThread.setDaemon(true);
daemonThread.start();
}
如果只有守護線程daemonThread,程序因為main線程的退出而退出。
注意點:
thread.setDaemon(true)必須在thread.start()之前設(shè)置,否則會跑出一個IllegalThreadStateException異常。你不能把正在運行的常規(guī)線程設(shè)置為守護線程。在Daemon線程中產(chǎn)生的新線程也是Daemon的
不要認為所有的應(yīng)用都可以分配給Daemon來進行服務(wù),比如讀寫操作或者計算邏輯
6. 主要方法
6.1 sleep(long millis)
源碼
public static native void sleep(long millis) throws InterruptedException;
注意點:
sleep是指線程被調(diào)用時,占著CPU不工作,形象地說明為“占著CPU睡覺”,此時,系統(tǒng)的CPU部分資源被占用,其他線程無法進入。
sleep方法不會釋放鎖。
示例:
public class ThreadDemo extends Thread {
private static Long i = 0L;
public void run() {
while (true) {
synchronized (ThreadDemo.class) {
i++;
try {
sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new ThreadDemo();
t.start();
Thread t1 = new ThreadDemo();
t1.start();
}
}
兩個線程(A、B)同時執(zhí)行,當線程A獲得同步鎖并進入同步塊時,線程B會處于BLOCKED狀態(tài)等待鎖。而當線程A執(zhí)行sleep后,線程A狀態(tài)為TIMED_WAITING,而由于sleep不會釋放鎖,所以線程B的狀態(tài)不會改變。
6.2 yield()
源碼
public static native void yield();
注意點:
調(diào)用yield方法會讓當前線程交出CPU權(quán)限,讓擁有相同優(yōu)先級的線程有獲取CPU執(zhí)行時間的機會
調(diào)用yield方法并不會讓線程進入
BLOCKED狀態(tài),而是讓線程重回RUNNABLE狀態(tài), 但不能保證迅速轉(zhuǎn)換。不會釋放鎖
6.3 isAlive()
表示線程當前是否為可用狀態(tài),如果線程已經(jīng)啟動,并且沒有死亡,則返回true,否則為false
源碼
public final native boolean isAlive();
6.4 join()
在很多情況下,主線程生成并起動了子線程,如果子線程里要進行大量的耗時的運算,主線程往往將于子線程之前結(jié)束,但是如果主線程處理完其他的事務(wù)后,需要用到子線程的處理結(jié)果,也就是主線程需要等待子線程執(zhí)行完成之后再結(jié)束,這個時候就要用到j(luò)oin()方法
源碼
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
public final void join() throws InterruptedException {
join(0);
}
注意點:
join方法是通過wait方法實現(xiàn)的,所以會釋放對象鎖。調(diào)用方線程狀態(tài)為
WAITING。join需要在start之后調(diào)用
示例一
public class ThreadDemo extends Thread {
private static Long i = 0L;
public void run() {
synchronized (this) {
while (true) {
i++;
try {
sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new ThreadDemo();
t.start();
Thread.sleep(1000);
t.join();
}
}
此處需要注意的是,此處t.join()不會被執(zhí)行,main線程會一直等待對象鎖而BLOCKED。
6.5 interrupt()
Thread.sleep、Thread.join、Object.wait等在檢查到線程的中斷狀態(tài)時,會拋出InterruptedException,同時會清除線程的中斷狀態(tài).
在java的線程Thread類中有三個方法,比較容易混淆,在這里解釋一下:
interrupt:設(shè)置線程的中斷狀態(tài)isInterrupt:線程是否中斷,不會清楚中斷狀態(tài)。interrupted:返回線程的上次的中斷狀態(tài),并清除中斷狀態(tài)。
示例
public class ThreadDemo extends Thread {
public void run() {
System.out.println("即將睡眠");
try {
Thread.sleep(1000 * 4);
} catch (InterruptedException e) {
System.out.println("被喚醒");
}
System.out.println("處理其他事情");
}
public static void main(String[] args) throws Exception {
Thread t = new ThreadDemo();
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
注意點:
Thread.interrupt()方法不會中斷一個正在運行的線程如果線程在調(diào)用
Object類的wait()、wait(long)或wait(long, int)方法,或者該類的join()、join(long)、join(long, int)、sleep(long)或sleep(long, int)方法過程中受阻,則其中斷狀態(tài)將被清除,它還將收到一個InterruptedException異常。synchronized在獲鎖的過程中是不能被中斷的,意思是說如果產(chǎn)生了死鎖,則不可能被中斷