• 线程dump


    当应用程序运行变慢或者发生故障时,可能通过分析java的Thread Dumps得到分析他们得到阻塞和存在瓶颈的线程。

    线程堆栈是虚拟机中线程(包括锁)状态的一个瞬间状态的快照,即系统在某一个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况。主要包含的信息包括

      1、线程名字,id,线程的数量等。

       2、线程的运行状态,锁的状态(锁被哪个线程持有,哪个线程在等待锁等)

       3、调用堆栈包含完整的类名,所执行的方法,源代码的行数等

       线程栈是瞬时快照包含线程状态以及调用关系,可以借助堆栈信息帮助分析很多性能问题。线程栈是瞬时记录,所以没有历史消息的回溯,经常需要打印几次做对比分析,并且在一般情况下都需要结合应用程序的日志进行问题定信。

    1、系统cpu过高
    2、性能瓶颈:如响应时间长但CPU资源并不高
    3、系统运行越来越慢,响应时间长
    4、系统挂起,长时间无响应或响应时间长
    5、线程死锁,死循环等
    6、由于线程数量太多导致的内存溢出(如无法创建线程等)

    Java线程原理

        线程同步

         多条线程之间可以同时执行,为了确保多线程在使用共享资源上面的通用性,使用线程同步保证在同一时间只能有一条线程可以访问共享资源。

         线程同步在Java中可以使用监视器。每个Java对象都有一个监视器,这个监视器只能被一个线程拥有。当一个线程要获得另外线程拥有的监视器时,需要进入等待队列直到线程释放监视器。

        线程的状态

        为了分析Thread Dump ,需要先了解线程的状态。线程的状态是在java.lang.Thread.State中。

     

     

    1. 新建状态(New) 新创建了一个线程对象。

    2. 就绪状态(Runnable) 线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

    3. 运行状态(Running) 就绪状态的线程获取了CPU,执行程序代码。

    4. 阻塞状态(Blocked) 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

    • 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    • 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    5. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    Jstack使用的关键字描述的线程状态与上边线程不太一样,所以可能理解上可能会出现混淆。虽然Java中的线程一样有上述中描述的5种状态,但在实际情况下线程新建状态和死亡状态持续很短,我们也并不太关心。大多时候我们关注的是运行状态/阻塞状态,

     

     

    详细过程可参考:

    • 当执行new Thread(Runnabler)后,新创建出来的线程处于new状态,这种线程不可能执行
    • 当执行thread.start()后,线程处于runnable状态,这种情况下只要得到CPU,就可以开始执行了。runnable状态的线程,会接受JVM的调度,进入running状态,但是具体何时会进入这个状态,是随机不可知的
    • running状态中的线程最为复杂,可能会进入runnable、waiting、timed_waiting、blocked、dead状态:
      • 如果CPU调度给了别的线程,或者执行了Thread.yield()方法,则进入runnable状态,但是也有可能立刻又进入running状态
      • 如果执行了Thread.sleep(long),或者thread.join(long),或者在锁对象上调用object.wait(long)方法,则会进入timed_waiting状态
      • 如果执行了thread.join(),或者在锁对象上调用了object.wait()方法,则会进入waiting状态
      • 如果进入了同步方法或者同步代码块,没有获取锁对象的话,则会进入blocked状态
      • 处于waiting状态中的线程,如果是因为thread.join()方法进入等待的,在目标thread执行完毕之后,会回到runnable状态;如果是因为object.wait()方法进入等待的话,在锁对象执行object.notify()或者object.notifyAll()之后会回到runnable状态
      • 处于timed_waiting状态中的线程,和waiting状态中的差不多,只不过是设定时间到了,就会回到runnable状态
      • 处于blocked状态中的线程,只有获取了锁之后,才会脱离阻塞状态
      • 当线程执行完毕,或者抛出了未捕获的异常之后,会进入dead状态,该线程结束

     

     

    我们需要重点关注RUNNABLE、BLOCKED、WAITING和TIME_WAITING四种状态,jstack打印的线程堆栈中也会时时出现。

    1)BLOCKED:就是线程在等待获取锁进入同步块或者同步方法中。两个死锁的线程即是Blocked。

    2)WAITING:比BLOCKED状态进步一些,指已经获得锁了,但由于有些条件不满足,要自己等会,调用object.wait()方法。等条件满足了,别的线程调用notify再叫我。另外也可以调用Thread.join()方法,顾名思义就是调用别的线程的join方法,让别人join进来先执行,那我就只能等会了。但是由于wait()和notify()以及notifyAll()用于协调对共享资源的存取,所以必须在synchronized块中使用。所以即便wait状态的线程被notfiy唤醒了,也需要再次获得锁,所以唤醒后进入Blocked状态。

    3)TIMED_WAITING:类比WAITING,差异是不需要notify()或者notifyAlL()方法唤醒,时间到了自己醒了。另外sleep比较好理解,就是让当前线程睡一会,与wait的区别是它不释放锁

    4)RUNNABLE不用多说,在JAVA虚拟机中已经在运行,但是在等待操作系统资源,比如CPU时间片。

    相关链接:

    https://blog.csdn.net/rachel_luo/article/details/8920596

    https://blog.csdn.net/zxp_cpinfo/article/details/54971115

  • 相关阅读:
    web前端
    touch.js——手机端的操作手势
    js实现touch移动触屏滑动事件
    Javascript闭包(Closure)
    javascript的垃圾回收机制与内存管理
    浏览器渲染页面
    Web前端面试题目汇总
    gulp VS grunt
    [编写高质量代码:改善java程序的151个建议]建议88 用枚举实现工厂方法模式更简单
    [编写高质量代码:改善java程序的151个建议]建议86,87 default值,valueOf
  • 原文地址:https://www.cnblogs.com/ken-jl/p/8999144.html
Copyright © 2020-2023  润新知