線程生命週期
線程的生命週期大致分爲五個部分
New:當我使用Thread類創建線程的時候,new一個Thread繼承類對象,這個時候其實還只是一個普通的Java對象,只有執行start()方法的時候,線程纔會創建
Runnable:執行start()方法後,變成Runnable狀態,這時候,雖然開啓線程,但是線程不會馬上執行,只有獲取cpu的時候權的時候纔會開始執行線程
Running:獲取cup時間片後,線程開始執行
Blocked:掛起,當前線程掛機,等待執行機會,變成Running狀態,或許變成Dead狀態,直接死亡,造成線程掛起的原因有很多,比如sleep()方法
Dead:線程死亡。
解析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)
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 */
}
}
}
上面是Thread類的start()方法,是開啓線程的入口
首先它會進行一個threadStatus線程狀態的判斷,如果不爲0,則會拋出異常。
當一個線程執行了start()方法後,threadStatus會發生改變,所以下次再執行start()方法,會拋出異常,所以說明線程是隻能啓動一次。
group.add(this):將線程加入一個線程組
start0()方式一個本地方法native,這是線程開啓的最終地方。
Thread和Runnable
1:創建線程的方式只有一種,那就是通過Thread類的構造函數創建
2:實現線程的方式有兩種,一種重寫Thread類的run方法,一種實現Runnable接口的run方法
3:一般我們實現Rnnable接口,在run()方法中完成線程業務邏輯編寫。然後將實現Runnable接口的對象放到Thread類的構造函數中,構造一個線程對象,使用該對象完成線程的開啓和其他關於線程的操作,如可以添加優先級,線程組等等。這樣做的原因有:
a:實現線程控制邏輯和業務邏輯的分類,
b:實現資源共享,如果我們繼承Thread類來創建線程那麼資源是不能共享,如thread1和thread2兩個線程是不能資源共享,因爲他們是兩個不同的對象,所有的資源都會在內存中創建兩份一樣的。
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
如果我們實現Runnable接口,那麼資源就是共享的,由於thread1和thread2線程是由runnable對象來構造,所以這兩個線程公用runnable對象的資源。
MyThread runnable = new MyThread();
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
Thread類
構造函數
在創建一個線程的時候可以給線程起一個線程名和將該線程添加一個線程組,強烈建議在創建線程的時候給線程起一個名字。
當然也可以在創建線程後還沒有調用start()方法前,使用SetName()方法添加。
線程的默認命名方式Thread-(從0開始遞增)
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
線程父子關係
查看init方法
有一個Thread parent = currentThread()獲取當前線程爲父線程
所以 a:一個線程的創建肯定是由另一個線程完成的
b:被創建線程的父線程是創建它的線程。
線程組
繼續查看init方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
如果線程沒有指定線程組,它會把線程添加到父線程的線程組中去。
守護線程
守護線程:一般用於處理一下後臺的工作,如JDK的垃圾回收,在正常情況下,若JVM中沒有一個非守護線程,則JVM的進程會退出。守護線程具備自動結束生命週期的特性
設置守護:通過setDaemon(true/false)
守護線程的作用:當你希望關閉某些線程的時候,或者退出JVM進程的時候,一些線程會自動關閉,這個時候你就可以設置線程爲守護線程