一 线程有哪几种状态

通过查看jdk的源码,从Thread类中看到有个描述线程状态的枚举类Thread$State,这个枚举类一共定义了6个枚举值。

状态 说明
NEW 线程被创建后,但是还没有执行任务时的状态
RUNNABLE 线程被启动,执行任务中
BLOCKED
WAITING 等待,必须让其他线程执行完后释放CPU资源,当前线程才能执行
TIMED_WAITING 有效时长的等待
TERMINATED 线程执行完任务后的状态

二 线程状态分析工具

jdk自带的命令行工具,也有可视化的图形工具

  1. jstatck

  2. jconsole

  3. jvisual

三 线程状态对应的场景

注意下面的代码都是放到一个main函数中执行的,不建议在junit单元测试中运行,因为junit单元测试方法执行完后会自动退出主线程(框架限制)。

3.1 NEW

在创建完一个线程后,这个线程的状态就是NEW。

  1. private static void test1(){
  2. Thread td1 = new Thread();
  3. System.out.println("thread state: " + td1.getState().name());
  4. }

3.2 RUNNABLE

  1. private static void test2(){
  2. Thread td = new Thread(() -> {
  3. for (int i = 0 ; i < Integer.MAX_VALUE; i += 1) {
  4. System.out.println(i);
  5. }
  6. }, "runnable-thread");
  7. System.out.println("thread state: " + td.getState().name());
  8. td.start();
  9. System.out.println("thread state: " + td.getState().name());
  10. }

使用jconsole工具可以看到,runnable-thread的状态是RUNNABLE。
Java线程的状态 - 图1

3.3 Blocked

  1. private static void test3(){
  2. Object lock = new Object();
  3. Thread td1 = new Thread(() -> {
  4. synchronized (lock) {
  5. System.out.println(Thread.currentThread().getName() + " invoke");
  6. try {
  7. Thread.sleep(30000L);
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. }, "Blocked_Thread_1");
  13. Thread td2 = new Thread(() -> {
  14. synchronized (lock) {
  15. System.out.println(Thread.currentThread().getName() + " invoke");
  16. try {
  17. Thread.sleep(20000L);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }, "Blocked_Thread_2");
  23. td1.start();
  24. td2.start();
  25. }

通过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

  1. private static void test4(){
  2. Thread td = new Thread(() ->{
  3. while(true) {
  4. }
  5. }, "Running_Thread_1");
  6. td.start();
  7. try {
  8. td.join();
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }

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状态。

  1. private static void test5(){
  2. Object lock = new Object();
  3. Thread td1 = new Thread(() -> {
  4. synchronized (lock) {
  5. System.out.println(Thread.currentThread().getName() + " invoke1");
  6. try {
  7. System.out.println(Thread.currentThread().getName() + " wait");
  8. lock.wait();
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println(Thread.currentThread().getName() + " invoke2");
  13. }
  14. }, "Waiting_Thread_1");
  15. Thread td2 = new Thread(() -> {
  16. synchronized (lock) {
  17. System.out.println(Thread.currentThread().getName() + " invoke");
  18. for(int i =1; i < 10; i ++) {
  19. try {
  20. Thread.sleep(10000);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. System.out.println(Thread.currentThread().getName() + " notify");
  26. lock.notify();
  27. }
  28. }, "Runnable_Thread_2");
  29. td1.start();
  30. try {
  31. Thread.sleep(10000);
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. td2.start();
  36. }

使用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

  1. private static void test6(){
  2. Thread td = new Thread(() -> {
  3. for (int i = 0 ; i < 100; i += 1) {
  4. System.out.println(i);
  5. }
  6. }, "runnable-thread");
  7. System.out.println("thread state: " + td.getState().name());
  8. td.start();
  9. try {
  10. Thread.sleep(1000L);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. while(true){
  15. System.out.println("thread state: " + td.getState().name());
  16. if(td.getState() == Thread.State.TERMINATED) {
  17. break;
  18. }
  19. }
  20. }

从程序执行结果最后一行可以看到,主线程结束之前,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

  1. <bean id="executorService" class="java.util.concurrent.ThreadPoolExecutor">
  2. <constructor-arg index="0" value="10"/>
  3. <constructor-arg index="1" value="50"/>
  4. <constructor-arg index="2" value="1800"/>
  5. <constructor-arg index="3" value="SECONDS"/>
  6. <constructor-arg index="4">
  7. <bean class="java.util.concurrent.ArrayBlockingQueue">
  8. <constructor-arg index="0" value="500"/>
  9. </bean>
  10. </constructor-arg>
  11. <constructor-arg index="5">
  12. <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
  13. </constructor-arg>
  14. </bean>

参考
1、Java线程状态分析,详情
2、Java线程的生命周期,详情