`

java 线程的几种状态

 
阅读更多

转自:http://www.jiacheo.org/blog/338

java thread的运行周期中, 有几种状态, 在 java.lang.Thread.State 中有详细定义和说明:

NEW 状态是指线程刚创建, 尚未启动

RUNNABLE 状态是线程正在正常运行中, 当然可能会有某种耗时计算/IO等待的操作/CPU时间片切换等, 这个状态下发生的等待一般是其他系统资源, 而不是锁, Sleep等

BLOCKED  这个状态下, 是在多个线程有同步操作的场景, 比如正在等待另一个线程的synchronized 块的执行释放, 或者可重入的 synchronized块里别人调用wait() 方法, 也就是这里是线程在等待进入临界区

WAITING  这个状态下是指线程拥有了某个锁之后, 调用了他的wait方法, 等待其他线程/锁拥有者调用 notify / notifyAll 一遍该线程可以继续下一步操作, 这里要区分 BLOCKED 和 WATING 的区别, 一个是在临界点外面等待进入, 一个是在理解点里面wait等待别人notify, 线程调用了join方法 join了另外的线程的时候, 也会进入WAITING状态, 等待被他join的线程执行结束

TIMED_WAITING  这个状态就是有限的(时间限制)的WAITING, 一般出现在调用wait(long), join(long)等情况下, 另外一个线程sleep后, 也会进入TIMED_WAITING状态

TERMINATED 这个状态下表示 该线程的run方法已经执行完毕了, 基本上就等于死亡了(当时如果线程被持久持有, 可能不会被回收)

下面谈谈如何让线程进入以上几种状态:

1. NEW, 这个最简单了,  
 
     static void NEW() {
          Thread t = new Thread ();
         System. out.println(t.getState());
    }
 
输出NEW
 
2. RUNNABLE, 也简单, 让一个thread start, 同时代码里面不要sleep或者wait等
 
   private static void RUNNABLE() {
         Thread t = new Thread(){
             
              public void run(){
                  for(int i=0; i<Integer.MAX_VALUE; i++){
                      System. out.println(i);
                 }
             }
             
         };
         
         t.start();
    }
 
 71e94764e28c7f8bbd3ef91c1c0088b4
 
3. BLOCKED, 这个就必须至少两个线程以上, 然后互相等待synchronized 块
          
     private static void BLOCKED() {
         
          final Object lock = new Object();
         
         Runnable run = new Runnable() {
             
              @Override
              public void run() {
                  for(int i=0; i<Integer.MAX_VALUE; i++){
                      
                       synchronized (lock) {
                          System. out.println(i);
                      }
                      
                 }
             }
         };
         
         Thread t1 = new Thread(run);
         t1.setName( “t1″);
         Thread t2 = new Thread(run);
         t2.setName( “t2″);
         
         t1.start();
         t2.start();
         
    }
 
8e9ad1eadf9d38c0b6c8cb024cb36c0c
这时候, 一个在RUNNABLE, 另一个就会在BLOCKED (等待另一个线程的 System.out.println.. 这是个IO操作, 属于系统资源, 不会造成WAITING等)
 
4. WAITING, 这个需要用到生产者消费者模型, 当生产者生产过慢的时候, 消费者就会等待生产者的下一次notify
 
     private static void WAITING() {
 
          final Object lock = new Object();
         Thread t1 = new Thread(){
              @Override
              public void run() {
                 
                  int i = 0;
                 
                  while(true ){
                       synchronized (lock) {
                           try {
                               lock.wait();
                          } catch (InterruptedException e) {
                          }
                          System. out.println(i++);
                      }
                 }
             }
         };
         
         Thread t2 = new Thread(){
              @Override
              public void run() {
                 
                  while(true ){
                       synchronized (lock) {
                           for(int i = 0; i< 10000000; i++){
                              System. out.println(i);
                          }
                          lock.notifyAll();
                      }
                      
                 }
             }
         };
         
         t1.setName( “^^t1^^”);
         t2.setName( “^^t2^^”);
         
         t1.start();
         t2.start();
    }
 
 b43a3d9b67bab266ffea4537fb043bba
 
5. TIMED_WAITING, 这个仅需要在4的基础上, 在wait方法加上一个时间参数进行限制就OK了.
 
把4中的synchronized 块改成如下就可以了.
 
synchronized (lock) {
   try {
      lock.wait(60 * 1000L);
   } catch (InterruptedException e) {
   }
   System. out .println(i++);
 }
 
 88d9047d8a709c2d63c695bcf58a0297
另外看stack的输出,  他叫 TIMED_WAITING(on  object monitor) , 说明括号后面还有其他的情况, 比如sleep, 我们直接把t2的for循环改成sleep试试:
 
synchronized (lock) {
    
    try {
          sleep(30*1000L);
    } catch (InterruptedException e) {
    }
    lock.notifyAll();
}
a37ef4c72c00e793f8b6c746d74fd4d9 
 
看到了吧, t2的state是 TIMED_WAITING( sleeping),  而t1依然是on object monitor , 因为t1还是wait在等待t2 notify, 而t2是自己sleep
 
另外, join操作也是进入 on object monitor
 
6. TERMINATED, 这个状态只要线程结束了run方法, 就会进入了…
 
    private static void TERMINATED() {
         Thread t1 = new Thread();
         t1.start();
         System. out.println(t1.getState());
          try {
             Thread. sleep(1000L);
         } catch (InterruptedException e) {
         }
         System. out.println(t1.getState());
    }
输出: 
RUNNABLE
TERMINATED
 
由于线程的start方法是异步启动的, 所以在其执行后立即获取状态有可能才刚进入RUN方法且还未执行完毕
 
 
废话了这么多, 了解线程的状态究竟有什么用?
所以说这是个钓鱼贴么…
 
好吧, 一句话, 在找到系统中的潜在性能瓶颈有作用.
 
当java系统运行慢的时候, 我们想到的应该先找到性能的瓶颈, 而jstack等工具, 通过jvm当前的stack可以看到当前整个vm所有线程的状态, 当我们看到一个线程状态经常处于
WAITING 或者 BLOCKED的时候, 要小心了, 他可能在等待资源经常没有得到释放(当然, 线程池的调度用的也是各种队列各种锁, 要区分一下, 比如下图)
6db341bbd7680bbc2e6ae37a66329397
这是个经典的并发包里面的线程池, 其调度队列用的是LinkedBlockingQueue, 执行take的时候会block住, 等待下一个任务进入队列中, 然后进入执行, 这种理论上不是系统的性能瓶颈, 找瓶颈一般先找自己的代码stack,再去排查那些开源的组件/JDK的问题
 
排查问题的几个思路:
 
0. 如何跟踪一个线程?
看到上面的stack输出没有, 第一行是内容是 threadName priority tid nid desc
更过跟踪tid, nid 都可以唯一找到该线程.
 
1. 发现有线程进入BLOCK, 而且持续好久, 这说明性能瓶颈存在于synchronized块中, 因为他一直block住, 进不去, 说明另一个线程一直没有处理好, 也就这个synchronized块中处理速度比较慢, 然后再深入查看. 当然也有可能同时block的线程太多, 排队太久造成.
 
2. 发现有线程进入WAITING, 而且持续好久, 说明性能瓶颈存在于触发notify的那段逻辑. 当然还有就是同时WAITING的线程过多, 老是等不到释放.
 
3. 线程进入TIME_WAITING 状态且持续好久的, 跟2的排查方式一样.
 
 
上面的黑底白字截图都是通过jstack打印出来的, 可以直接定位到你想知道的线程的执行栈, 这对java性能瓶颈的分析是有极大作用的.
 
NOTE: 上面所有代码都是为了跟踪线程的状态而写的, 千万不要在线上应用中这么写…
分享到:
评论

相关推荐

    基于java 线程的几种状态(详解)

    下面小编就为大家带来一篇基于java 线程的几种状态(详解)。小编觉得挺不错的,现在就想给大家,也给大家做个参考。一起跟随小编过来看看吧

    关于线程(java)两天的课件

    线程入门,创建线程、线程的几种状态、线程排序、线程池入门。

    Java 多线程介绍

    Java 多线程介绍 线程的几种状态 1

    在java中的线程的转换图

    在java中的线程转换的总描述,结合了所有的java有关线程的状态转移图

    简单谈谈Java 中的线程的几种状态

    主要介绍了简单谈谈Java 中的线程的几种状态的相关资料,需要的朋友可以参考下

    Java多线程教程吐血整理干货.md

    线程的几种状态 sleep方法和wait方法的区别 stop,suspend,resume等方法为什么会被遗弃 interrupt,interrupted,isInterrupted方法区别 join方法 yield方法 多线程 进程和线程 进程与线程最主要的区别是它们是操作系统...

    个人总结的深入java多线程开发

    4)几种多线程代码写法 10 5)一个超时自动退出程序的类 12 6)同步锁synchronized 13 7)一个程序执行1秒之后自动退出 13 8)线程的状态 14 9)线程阻塞的条件(重要) 14 10) Interrupt()注意事项 16 三. 线程之间协作 17 ...

    Java中的线程与线程池.pptx

    首先,阐述了为什么需要线程、Java中实现线程的几种方式,线程的多种状态切换;然后,介绍了为什么需要线程池,JDK自带的线程池实现方式ThreadPoolExecutor的使用及其原理,最后强调ThreadPoolExecutor应用的注意点...

    Java程序设计案例教程-第8章-多线程编程.pptx

    第4页 主要内容 8.1 Java线程模型 8.2 创建线程 8.3 同步与线程间通信 8.4 获取线程状态 8.5 本章小结 8.6 思考和练习 Java程序设计案例教程-第8章-多线程编程全文共36页,当前为第4页。 8.1 Java线程模型 Java对多...

    java面试题(线程和JSP及EJB部分).pdf

    1、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable 接口 用synchronized 关键字修饰同步方法 反对...

    中软公司JAVA培训资料.doc

    6、线程的基本概念、线程的基本状态以及状态之间的关系 7、线程的同步、如何实现线程的同步 8、几种常用的数据结构及内部实现原理。 9、Socket通信(TCP、UDP区别及Java实现方式) **10、Java的事件委托机制和...

    多线程,高并发.pdf

    1. stop() 和 suspend() 方法为何不推荐使用? 2. sleep() 和 wait() 有什么区别? 3. 同步和异步有何异同,在什么情况下分别使用他们? 4. 当一个线程进入一个对象的一个 ...6. 概括的解释下线程的几种可用状态。

    java笔试题大集合及答案(另附各大公司笔试题)

    60、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接口 用synchronized关键字修饰同步方法 反对使用...

    【java系列文章】java 基础知识

    4.概括的解释下Java线程的几种可用状态? 中级 1.简述Java同步方法和同步代码块的区别 ? 2.HashMap和Hashtable有什么区别? 3.简述Java堆的结构? 什么是堆中的永久代(Perm Gen space)? 4.简述 Dubbo 和 Spring Cloud ...

    后端JAVA虚拟机JVM调优必备工具

    二、此工具线程的几种状态 1.死锁,Deadlock(重点关注)  2.执行中,Runnable(重点关注)  3.等待资源,Waiting on condition(重点关注)  4.等待监控器检查资源,Waiting on monitor  5.暂停,Suspended  ...

    Java中停止线程执行的方法

    一、暂停或停止线程的理论 在Java编程中,要暂停或停止当前正在运行的线程,有几种方法。对于把线程转入睡眠Sleep状态,使用Thread.sleep()是最正确的方式。或许有人会问,为什么不使用等待wait()或通知notify()?要...

    Java的线程机制

    Java中线程4个状态之间的转换;并结合例子说明了两种创建线程的方法。 线程是指程序中能顺序执行的一个序列。一个线程只有一个入口点但可能有几个出口点不过,每个时刻的执行点总是只有一个。线程是不能独立...

    Java常见面试题208道.docx

    15.java 中 IO 流分为几种? 16.BIO、NIO、AIO 有什么区别? 17.Files的常用方法都有哪些? 二、容器 18.java 容器都有哪些? 19.Collection 和 Collections 有什么区别? 20.List、Set、Map 之间的区别是什么? 21....

    JAVA上百实例源码以及开源项目

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    JAVA上百实例源码以及开源项目源代码

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

Global site tag (gtag.js) - Google Analytics