每一个 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标识来中止线程