一 线程有哪几种状态
通过查看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>
