一 线程有哪几种状态
通过查看jdk的源码,从Thread类中看到有个描述线程状态的枚举类Thread$State,这个枚举类一共定义了6个枚举值。
状态 | 说明 |
---|---|
NEW | 线程被创建后,但是还没有执行任务时的状态 |
RUNNABLE | 线程被启动,执行任务中 |
BLOCKED | |
WAITING | 等待,必须让其他线程执行完后释放CPU资源,当前线程才能执行 |
TIMED_WAITING | 有效时长的等待 |
TERMINATED | 线程执行完任务后的状态 |
二 线程状态分析工具
jdk自带的命令行工具,也有可视化的图形工具
jstatck
jconsole
jvisual
三 线程状态对应的场景
注意下面的代码都是放到一个main函数中执行的,不建议在junit单元测试中运行,因为junit单元测试方法执行完后会自动退出主线程(框架限制)。
3.1 NEW
在创建完一个线程后,这个线程的状态就是NEW。
private static void test1(){
Thread td1 = new Thread();
System.out.println("thread state: " + td1.getState().name());
}
3.2 RUNNABLE
private static void test2(){
Thread td = new Thread(() -> {
for (int i = 0 ; i < Integer.MAX_VALUE; i += 1) {
System.out.println(i);
}
}, "runnable-thread");
System.out.println("thread state: " + td.getState().name());
td.start();
System.out.println("thread state: " + td.getState().name());
}
使用jconsole工具可以看到,runnable-thread的状态是RUNNABLE。
3.3 Blocked
private static void test3(){
Object lock = new Object();
Thread td1 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " invoke");
try {
Thread.sleep(30000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Blocked_Thread_1");
Thread td2 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " invoke");
try {
Thread.sleep(20000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Blocked_Thread_2");
td1.start();
td2.start();
}
通过jstatck工具分析此程序的进程,结果如下:
“Blocked_Thread_2” #11 prio=5 os_prio=31 tid=0x00007fa1a98ba800 nid=0x3e03 waiting for monitor entry [0x0000700009fd4000]
java.lang.Thread.State: BLOCKED (on object monitor)
at tech.zeng.learning.develop.juc.ThreadStateSeek.lambda$test3$2(ThreadStateSeek.java:64)
- waiting to lock <0x000000079573ab00> (a java.lang.Object)
at tech.zeng.learning.develop.juc.ThreadStateSeek$$Lambda$2/932172204.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
“Blocked_Thread_1” #10 prio=5 os_prio=31 tid=0x00007fa1a8948000 nid=0x4303 waiting on condition [0x0000700009ed1000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at tech.zeng.learning.develop.juc.ThreadStateSeek.lambda$test3$1(ThreadStateSeek.java:54)
- locked <0x000000079573ab00> (a java.lang.Object)
at tech.zeng.learning.develop.juc.ThreadStateSeek$$Lambda$1/1587487668.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
1 可以看出Blocked_Thread_1先启动获取到lock对象的锁,然后进入休眠(sleep只释放CPU资源,不释放锁资源),对应的线程状态是TIMED_WAITING。 2 Blocked_Thread_2启动后,开始执行任务,但是检测到lock对象的锁被其他线程占用,无法继续进行下去,任务被阻塞。
3.4 WAITING
使用Thread.join()方法,或者Object.wait()方法,都会使当前线程进入WAITING状态,其他线程继续执行任务。
示例1
private static void test4(){
Thread td = new Thread(() ->{
while(true) {
}
}, "Running_Thread_1");
td.start();
try {
td.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jstack分析的结果如下:
“Runnable_Thread_1” #10 prio=5 os_prio=31 tid=0x00007ffc5487c800 nid=0x3803 runnable [0x0000700010b18000]
java.lang.Thread.State: RUNNABLE
at tech.zeng.learning.develop.juc.ThreadStateSeek.lambda$main$0(ThreadStateSeek.java:15)
at tech.zeng.learning.develop.juc.ThreadStateSeek$$Lambda$1/1199823423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
“main” #1 prio=5 os_prio=31 tid=0x00007ffc54802800 nid=0x2703 in Object.wait() [0x000070000fbeb000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000079573af20> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1252)
- locked <0x000000079573af20> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1326)
at tech.zeng.learning.develop.juc.ThreadStateSeek.main(ThreadStateSeek.java:21)
3.5 TIMED_WAITING
调用Thread.wait(time)方法,或者Thread.sleep(time)方法都会使线程进入TIME_WAITING状态。
private static void test5(){
Object lock = new Object();
Thread td1 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " invoke1");
try {
System.out.println(Thread.currentThread().getName() + " wait");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " invoke2");
}
}, "Waiting_Thread_1");
Thread td2 = new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " invoke");
for(int i =1; i < 10; i ++) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " notify");
lock.notify();
}
}, "Runnable_Thread_2");
td1.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
td2.start();
}
使用jstack分析的结果如下:
“Runnable_Thread_2” #11 prio=5 os_prio=31 tid=0x00007ff1be02f000 nid=0xe07 waiting on condition [0x0000700010855000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at tech.zeng.learning.develop.juc.ThreadStateSeek.lambda$test5$5(ThreadStateSeek.java:121)
- locked <0x0000000795836a80> (a java.lang.Object)
at tech.zeng.learning.develop.juc.ThreadStateSeek$$Lambda$2/565760380.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
“Waiting_Thread_1” #10 prio=5 os_prio=31 tid=0x00007ff1bd8c5000 nid=0x4503 in Object.wait() [0x0000700010752000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000795836a80> (a java.lang.Object)
at java.lang.Object.wait(Object.java:502)
at tech.zeng.learning.develop.juc.ThreadStateSeek.lambda$test5$4(ThreadStateSeek.java:105)
- locked <0x0000000795836a80> (a java.lang.Object)
at tech.zeng.learning.develop.juc.ThreadStateSeek$$Lambda$1/930990596.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
1 Waiting_Thread_1先启动,先获取到lock的对象锁,调用lock.wait()后释放对象锁,当前线程会进入WAITING状态。 2 Runnable_Thread_2获取锁后开始执行,然后休眠10秒,这时线程的状态是TIMED_WAITING状态。
3.6 Terminated
private static void test6(){
Thread td = new Thread(() -> {
for (int i = 0 ; i < 100; i += 1) {
System.out.println(i);
}
}, "runnable-thread");
System.out.println("thread state: " + td.getState().name());
td.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
while(true){
System.out.println("thread state: " + td.getState().name());
if(td.getState() == Thread.State.TERMINATED) {
break;
}
}
}
从程序执行结果最后一行可以看到,主线程结束之前,Runnable-Thread的线程状态是TERMINATED。
四 Blocked和Waiting的区别
4.1 Blocked状态,当线程去访问一个加锁的方法时,如果已有其他线程持有锁,那么当前线程出于阻塞状态。
4.2 waiting状态,当前线程调用Object.wait(),Thread.join(),LockSupport.park()方法后,线程处于等待状态。
4.3 blocked是被动的标记,waiting是线程主动操作的。
4.4 如果说的再深入一点,waiting状态的线程在其他操作被唤醒以后,需要进入同步队列中去竞争锁,而进入同步队列以后,如果已经有其他线程获持有锁,那么线程又会变成blocked状态。所以说blocked状态是waiting状态线程被重新唤醒以后的必经状态。
五 创建线程池bean
<bean id="executorService" class="java.util.concurrent.ThreadPoolExecutor">
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="50"/>
<constructor-arg index="2" value="1800"/>
<constructor-arg index="3" value="SECONDS"/>
<constructor-arg index="4">
<bean class="java.util.concurrent.ArrayBlockingQueue">
<constructor-arg index="0" value="500"/>
</bean>
</constructor-arg>
<constructor-arg index="5">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</constructor-arg>
</bean>