每一個 Java 程序都有一個缺省的主線程,對於 Java 應用程序,主線程是 main()方法執行的線索;對於 Applet 程序,主線程是指揮瀏覽器加載並執行 Java Applet 程序的線索。要想實現多線程,必須在主線程中建立新的線程對象。任何線程通常具備五種狀態,即建立、就緒、運行、阻塞、終止。java
一、新生狀態瀏覽器
在程序中用構造方法(new操做符)建立一個新線程時,如new Thread(r),該線程就是建立狀態,此時它已經有了相應的內存空間和其它資源,可是尚未開始執行。多線程
二、就緒狀態ide
新建線程對象後,調用該線程的 start()方法就能夠啓動線程。當線程啓動時,線程進入就緒狀態(runnable)。因爲尚未分配CPU,線程將進入線程隊列排隊,等待 CPU 服務,這代表它已經具備了運行條件。當系統挑選一個等待執行的Thread對象後,它就會從等待執行狀態進入執行狀態。系統挑選的動做稱之爲「CPU調度"。一旦得到CPU線程就進入運行狀態並自動調用本身的run方法。this
三、運行狀態
spa
當就緒狀態的線程被調用並得到處理器資源時,線程就進入了運行狀態。此時,自動調用該線程對象的 run()方法。 run()方法定義了該線程的操做和功能。運行狀態中的線程執行本身的run方法中代碼。直到調用其餘方法或者發生阻塞而終止。線程
四、阻塞狀態3d
一個正在執行的線程在某些特殊狀況下,如被人爲掛起或須要執行耗時的輸入輸出操做時,將讓出 CPU 並暫時停止本身的執行,進入堵塞狀態。在可執行狀態下,如果調用 sleep()、 suspend()、 wait()等方法,線程都將進入堵塞狀態。堵塞時,線程不能進入排隊隊列,只有當引發堵塞的緣由被消除後,線程轉入就緒狀態。從新到就緒隊列中排隊等待,這時被CPU調度選中後會從原來中止的位置開始繼續執行。code
記住:阻塞被消除後是回到就緒狀態,不是運行狀態。對象
五、死亡狀態
線程調用 stop()方法、destory()方法或 run()方法執行結束後,線程即處於死亡狀態。處於死亡狀態的線程不具備繼續運行的能力。
不推薦使用stop()方法【會產生異常】 destory()方法【destory是強制終止,不會釋放鎖】
推薦使用boolen標識來中止線程,以下方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class
TestThraed
implements
Runnable{
private
boolean
flag =
true
;
//線程使用標識
@Override
public
void
run() {
while
(flag) {
for
(
int
i =
0
; i <
10
; i++) {
System.out.println(
"TestThread在運行"
+i);
}
}
}
//中止線程
public
void
stop(){
//若是是extends Thread方式實現多線程。不能使用stop方法名。由於Thread類中對stop修飾爲final不可重寫
this
.flag =
false
;
}
}
|
能夠經過getState()方法來獲取線程當前的狀態:NEW 、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
線程的狀態經典圖:
分析上圖:
一、線路1:新生-->就緒(Runnable)-->運行(Running)-->sleep或者join形成阻塞-->回到就緒(Runnable)-->運行(Running)-->死亡
二、線路2:新生-->就緒(Runnable)-->運行(Running)-->遇到synchronized,須要等待鎖的釋放。釋放完成後-->回到就緒(Runnable)-->運行(Running)-->死亡
三、線路3:新生-->就緒(Runnable)-->運行(Running)-->遇到wait形成的等待須要喚醒notify。醒了後-->回到就緒(Runnable)-->運行(Running)-->死亡
1
2
3
4
5
6
7
8
9
10
|
//取得線程的名字
Thread t = Thread.currentThread();
String name = t.getName();
//設置線程的名字
SetNameThreadDemo tt =
new
SetNameThreadDemo();
//繼承Thread或者實現Runnable接口的線程類
tt.setName(
"test thread"
);
//判斷線程是否啓動
調用start()方法以前t.isAlive() =
false
t.start();
調用start()方法以後t.isAlive() =
true
|
線程的合併:join
線程的合併是指將某一個線程A在調用A.join()方法合併到正在運行的另外一個線程B中,此時線程B處於阻塞狀態須要等到線程A執行完畢後纔開始線程B的繼續執行,代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public
class
JoinDemo {
public
static
void
main(String[] args)
throws
InterruptedException {
TestThread t =
new
TestThread();
Thread t1 =
new
Thread(t);
t1.start();
for
(
int
i =
0
; i <
100
; i++) {
/**
* 當main線程中的i等於50的時候,就把t1線程合併到main線程中執行。此時main線程是處於阻塞狀態
* 直到t1線程執行完成後,main纔開始繼續執行
*/
if
(
50
==i) {
t1.join();
}
System.out.println(
"main.."
+i);
}
}
}
class
TestThread
implements
Runnable{
@Override
public
void
run() {
for
(
int
i =
0
; i <
100
; i++) {
System.out.println(
"join.."
+i);
}
}
}
|
join的執行結果以下:
1
2
3
4
5
6
7
8
9
10
|
main..
0
.....省略.......
main..
17
join..
0
join..
1
.....省略.......
main..
49
//當main的i=50的時候就把t1合併到main線程中,直到t1線程執行完成後,纔開始執行main線程。
join..
5
- join..
99
main..
50
main..
51
- main..
99
|
線程的暫停:yield
該暫停方法暫停的時候不必定就暫停了,取決於CPU,假如剛暫停CPU調度又調到了該線程那就又啓動了.....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
YieldDemo {
public
static
void
main(String[] args)
throws
InterruptedException {
TestThread1 t =
new
TestThread1();
Thread t1 =
new
Thread(t);
t1.start();
for
(
int
i =
0
; i <
100
; i++) {
//當main線程中的i是20的倍數時,就暫停main線程
if
(i%
20
==
0
) {
Thread.yield();
//yield寫在哪一個線程體中,就暫停哪一個線程。這裏是在main裏,就暫停main線程
System.out.println(
"main線程暫停"
);
}
System.out.println(
"main.."
+i);
}
}
}
class
TestThread1
implements
Runnable{
@Override
public
void
run() {
for
(
int
i =
0
; i <
100
; i++) {
System.out.println(
"join.."
+i);
}
}
}
|
jield的執行結果以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
main線程暫停
main..
0
main..
19
main線程暫停
main..
20
main..
39
main線程暫停
main..
40
main..
59
main線程暫停
main..
79
main線程暫停
main..
80
main..
84
join..
0
join..
1
|
線程的(睡眠)暫停:sleep 休眠不釋放鎖【抱着鎖睡覺】
實例:10秒倒計時,當前線程每睡1秒就打印一個數字
1
2
3
4
5
6
7
8
9
10
|
public
static
void
main(String[] args)
throws
InterruptedException {
int
num =
10
;
while
(
true
) {
System.out.println(num--);
Thread.sleep(
1000
);
if
(num<=
0
) {
break
;
}
}
}
|
守護線程(線程的後臺運行):thread.setDaemon(true);
線程的後臺運行
一、對 Java 程序來講,只要還有一個前臺線程在運行,這個進程就不會結束,若是一個進程中只有後臺線程在運行,這個進程就會結束。
二、若是某個線程對象在啓動(調用 start()方法)以前調用了 setDaemon(true)方法,這個線程就變成了後臺線程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public
class
ThreadDaemon {
public
static
void
main(String[] args) {
ThreadTest t =
new
ThreadTest();
Thread thread =
new
Thread(t);
thread.setDaemon(
true
);
//設置後臺運行
thread.start();
}
}
class
ThreadTest
implements
Runnable{
@Override
public
void
run() {
while
(
true
) {
System.out.println(Thread.currentThread().getName()+
" is running"
);
}
}
}
|
一、形成線程阻塞的方法?
阻塞線程的方法:join、yield、sleep 和Object的wait()方法
二、Java的守護進程(後臺進程)?
設置線程爲後臺進程運行:setDaemon(true) 若是一個進程中只有後臺線程在運行,這個進程就會結束。
三、形成線程阻塞後,線程回到哪一個狀態了?
經過join、yield、sleep形成線程阻塞後是回到了就緒狀態
三、哪些狀態以後是回到就緒狀態?
a)經過join、yield、sleep形成線程阻塞後是回到了就緒狀態
b)遇到synchronized後
c)遇到Object的等待wait方法後
四、sleep會釋放鎖嗎?
sleep不會釋放鎖【它會抱着鎖睡覺】
五、線程都有哪些狀態?具體是怎麼運行的?
線程有:建立、就緒、運行、阻塞、終止。5種狀態
1.經過new關鍵字建立後,進入到新生狀態
2.調用start後進入就緒狀態
3.CPU調度到本線程後,本線程開始執行。進入到運行狀態
4.運行中遇到join,yield,sleep形成阻塞,進入阻塞狀態。阻塞完成後,又回到就緒狀態
5.線程正常執行完,或者遇到異常終止後,進入死亡狀態
六、終止線程有哪幾種方法?
線程調用 stop()方法、destory()方法或 run()方法執行結束後,線程即處於死亡狀態。處於死亡狀態的線程不具備繼續運行的能力。
推薦使用boolen標識來中止線程