Java多线程:死锁,java多线程

时间:2019-10-05 23:07来源:计算机教程
Java多线程:死锁,java多线程 周末看到一个用jstack查看死锁的例子。昨天晚上总结了一下jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令。供大家参考    姓名:郭金  学号:171

Java多线程:死锁,java多线程

周末看到一个用jstack查看死锁的例子。昨天晚上总结了一下jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令。供大家参考 

 

姓名:郭金  学号:17101223407

1.Jstack 

1.1 jstack能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。如下图所示

vnsc5858威尼斯城官网 1

注:这个和thread dump是同样的结果。但是thread dump是用kill -3 pid命令,还是服务器上面少用kill为妙 

1.2   命名行格式 
jstack [ option ] pid 
jstack [ option ] executable core 
jstack [ option ] [[email protected]]remote-hostname-or-IP 
最常用的还是jstack  pid 

1.3   在thread dump中,要留意下面几种状态 
死锁,Deadlock(重点关注) 
等待资源,Waiting on condition(重点关注) 
•  等待获取监视器,Waiting on monitor entry(重点关注) 
阻塞,Blocked(重点关注) 
•  执行中,Runnable 
•  暂停,Suspended 
•  对象等待中,Object.wait() 或 TIMED_WAITING 
•  停止,Parked 

下面有详细的例子讲这种分析,大家参考原著 

http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html 

【嵌牛导读】:之前看到一个用jstack查看死锁的例子。总结了一下:jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令。供大家参考。

**线程名称 所属 解释说明 **  

Attach Listener JVM Attach Listener 线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。 如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。  
Signal Dispatcher JVM 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather 线程去进行分发到各个不同的模块处理命令,并且返回处理结果。 signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。  
CompilerThread0 JVM 用来调用JITing,实时编译装卸class 。 通常,jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加,例如:CompilerThread1  
Concurrent Mark-Sweep GC Thread JVM 并发标记清除垃圾回收器(就是通常所说的CMS GC)线程, 该线程主要针对于老年代垃圾回收。ps:启用该垃圾回收器,需要在jvm启动参数中加上: -XX: UseConcMarkSweepGC 
DestroyJavaVM JVM 执行main()的线程在main执行完后调用JNI中的 jni_DestroyJavaVM() 方法唤起DestroyJavaVM 线程。   JVM在 Jboss 服务器启动之后,就会唤起DestroyJavaVM线程,处于等待状态,等待其它线程(java线程和native线程)退出时通知它卸载JVM。线程退出时,都会判断自己当前是否是整个JVM中最后一个非deamon线程,如果是,则通知DestroyJavaVM 线程卸载JVM。 ps: 
扩展一下: 
1.如果线程退出时判断自己不为最后一个非deamon线程,那么调用thread->exit(false) ,并在其中抛出thread_end事件,jvm不退出。 
2.如果线程退出时判断自己为最后一个非deamon线程,那么调用before_exit() 方法,抛出两个事件:  事件1:thread_end 线程结束事件、事件2:VM的death事件。 
然后调用thread->exit(true) 方法,接下来把线程从active list卸下,删除线程等等一系列工作执行完成后,则通知正在等待的DestroyJavaVM 线程执行卸载JVM操作。 
ContainerBackgroundProcessor 线程 JBOSS 它是一个守护线程, 在jboss服务器在启动的时候就初始化了,主要工作是定期去检查有没有Session过期.过期则清除.  参考:http://liudeh-009.iteye.com/blog/1584876  Dispatcher-Thread-3  线程 Log4j  Log4j具有异步打印日志的功能,需要异步打印日志的Appender都需要注册到 AsyncAppender对象里面去,由AsyncAppender进行监听,决定何时触发日志打印操作。 AsyncAppender如果监听到它管辖范围内的Appender有打印日志的操作,则给这个Appender生成一个相应的event,并将该event保存在一个buffuer区域内。  Dispatcher-Thread-3线程负责判断这个event缓存区是否已经满了,如果已经满了,则将缓存区内的所有event分发到Appender容器里面去,那些注册上来的Appender收到自己的event后,则开始处理自己的日志打印工作。 Dispatcher-Thread-3线程是一个守护线程。 Finalizer线程 JVM 这个线程也是在main线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的finalize()方法;关于Finalizer线程的几点: 
  1) 只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行; 
  2) 该线程也是daemon线程,因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法,JVM也会退出; 
  3) JVM在垃圾收集时会将失去引用的对象包装成Finalizer对象(Reference的实现),并放入ReferenceQueue,由Finalizer线程来处理;最后将该Finalizer对象的引用置为null,由垃圾收集器来回收; 
  4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做,很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难; Gang worker#0 JVM JVM 用于做新生代垃圾回收(monir gc)的一个线程。#号后面是线程编号,例如:Gang worker#1 GC Daemon JVM GC Daemon 线程是JVM为RMI提供远程分布式GC使用的,GC Daemon线程里面会主动调用System.gc()方法,对服务器进行Full GC。 其初衷是当 RMI 服务器返回一个对象到其客户机(远程方法的调用方)时,其跟踪远程对象在客户机中的使用。当再没有更多的对客户机上远程对象的引用时,或者如果引用的“租借”过期并且没有更新,服务器将垃圾回收远程对象。 
不过,我们现在jvm启动参数都加上了-XX: DisableExplicitGC配置,所以,这个线程只有打酱油的份了。 IdleRemover JBOSS Jboss连接池有一个最小值, 该线程每过一段时间都会被Jboss唤起,用于检查和销毁连接池中空闲和无效的连接,直到剩余的连接数小于等于它的最小值。 Java2D Disposer JVM  这个线程主要服务于awt的各个组件。 说起该线程的主要工作职责前,需要先介绍一下Disposer类是干嘛的。 Disposer提供一个addRecord方法。 如果你想在一个对象被销毁前再做一些善后工作,那么,你可以调用Disposer#addRecord方法,将这个对象和一个自定义的DisposerRecord接口实现类,一起传入进去,进行注册。  
          Disposer类会唤起“Java2D Disposer”线程,该线程会扫描已注册的这些对象是否要被回收了,如果是,则调用该对象对应的DisposerRecord实现类里面的dispose方法。 
          Disposer实际上不限于在awt应用场景,只是awt里面的很多组件需要访问很多操作系统资源,所以,这些组件在被回收时,需要先释放这些资源。 InsttoolCacheScheduler_ 
QuartzSchedulerThread Quartz 
InsttoolCacheScheduler_QuartzSchedulerThread是Quartz的主线程,它主要负责实时的获取下一个时间点要触发的触发器,然后执行触发器相关联的作业 原理大致如下: 
         Spring和Quartz结合使用的场景下,Spring IOC容器初始化时会创建并初始化Quartz线程池(TreadPool),并启动它。刚启动时线程池中每个线程都处于等待状态,等待外界给他分配Runnable(持有作业对象的线程)。 
         继而接着初始化并启动Quartz的主线程(InsttoolCacheScheduler_QuartzSchedulerThread),该线程自启动后就会处于等待状态。等待外界给出工作信号之后,该主线程的run方法才实质上开始工作。run中会获取JobStore中下一次要触发的作业,拿到之后会一直等待到该作业的真正触发时间,然后将该作业包装成一个JobRunShell对象(该对象实现了Runnable接口,其实看是上面TreadPool中等待外界分配给他的Runnable),然后将刚创建的JobRunShell交给线程池,由线程池负责执行作业。 
线程池收到Runnable后,从线程池一个线程启动Runnable,反射调用JobRunShell中的run方法,run方法执行完成之后, TreadPool将该线程回收至空闲线程中 InsttoolCacheScheduler_Worker-2 Quartz InsttoolCacheScheduler_Worker-2线程就是ThreadPool线程的一个简单实现,它主要负责分配线程资源去执行 
InsttoolCacheScheduler_QuartzSchedulerThread线程交给它的调度任务(也就是JobRunShell)。  
JBossLifeThread Jboss    Jboss主线程启动成功,应用程序部署完毕之后将JBossLifeThread线程实例化并且start,JBossLifeThread线程启动成功之后就处于等待状态,以保持Jboss Java进程处于存活中。  所得比较通俗一点,就是Jboss启动流程执行完毕之后,为什么没有结束? 就是因为有这个线程hold主了它。 牛b吧~~  JBoss System Threads(1)-1 Jboss   该线程是一个socket服务,默认端口号为: 1099。 主要用于接收外部naming service(Jboss  JNDI)请求。  
JCA PoolFiller Jboss     该线程主要为JBoss内部提供连接池的托管。  简单介绍一下工作原理 : 
    Jboss内部凡是有远程连接需求的类,都需要实现ManagedConnectionFactory接口,例如需要做JDBC连接的 
XAManagedConnectionFactory对象,就实现了该接口。然后将XAManagedConnectionFactory对象,还有其它信息一起包装到InternalManagedConnectionPool对象里面,接着将InternalManagedConnectionPool交给PoolFiller对象里面的列队进行管理。   JCA PoolFiller线程会定期判断列队内是否有需要创建和管理的InternalManagedConnectionPool对象,如果有的话,则调用该对象的fillToMin方法, 触发它去创建相应的远程连接,并且将这个连接维护到它相应的连接池里面去。  
JDWP Event Helper Thread JVM            
JDWP是通讯交互协议,它定义了调试器和被调试程序之间传递信息的格式。它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的JVMTI和JDI的通信通畅。  该线程主要负责将JDI事件映射成JVMTI信号,以达到调试过程中操作JVM的目的。   

JDWP Transport Listener: dt_socket JVM 该线程是一个Java Debugger的监听器线程,负责受理客户端的debug请求。 通常我们习惯将它的监听端口设置为8787。 
Low Memory Detector JVM 这个线程是负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间。 
process reaper JVM     该线程负责去执行一个 OS 命令行的操作。 
Reference Handler JVMvnsc5858威尼斯城官网,         JVM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问

 

http://www.bkjia.com/Javabc/1307476.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javabc/1307476.htmlTechArticleJava多线程:死锁,java多线程 周末看到一个用jstack查看死锁的例子。昨天晚上总结了一下jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命...

【嵌牛鼻子】:java多线程、死锁

【嵌牛提问】:说到多线程,又和c中的pthread有何区别?它的各操作的命令又如何表示呢?

【嵌牛正文】:

1.Jstack

1.1  jstack能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。如下图所示

vnsc5858威尼斯城官网 2

注:这个和thread dump是同样的结果。但是thread dump是用kill -3 pid命令,还是服务器上面少用kill为妙

1.2  命名行格式

jstack [ option ] pid

jstack [ option ] executable core

jstack [ option ] [server-id@]remote-hostname-or-IP

最常用的还是jstack  pid

1.3  在thread dump中,要留意下面几种状态

死锁,Deadlock(重点关注)

等待资源,Waiting on condition(重点关注)

•  等待获取监视器,Waiting on monitor entry(重点关注)

阻塞,Blocked(重点关注)

•  执行中,Runnable

•  暂停,Suspended

•  对象等待中,Object.wait() 或 TIMED_WAITING

•  停止,Parked

下面有详细的例子讲这种分析,大家参考原著

http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html

1.4  在thread dump中,有几种线程的定义如下

线程名称 所属 解释说明

Attach Listener JVM Attach Listener 线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。 如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。

Signal Dispatcher JVM 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather 线程去进行分发到各个不同的模块处理命令,并且返回处理结果。 signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。

CompilerThread0 JVM 用来调用JITing,实时编译装卸class 。 通常,jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加,例如:CompilerThread1

Concurrent Mark-Sweep GC Thread JVM 并发标记清除垃圾回收器(就是通常所说的CMS GC)线程, 该线程主要针对于老年代垃圾回收。ps:启用该垃圾回收器,需要在jvm启动参数中加上: -XX: UseConcMarkSweepGC

DestroyJavaVM JVM 执行main()的线程在main执行完后调用JNI中的 jni_DestroyJavaVM() 方法唤起DestroyJavaVM 线程。  JVM在 Jboss 服务器启动之后,就会唤起DestroyJavaVM线程,处于等待状态,等待其它线程(java线程和native线程)退出时通知它卸载JVM。线程退出时,都会判断自己当前是否是整个JVM中最后一个非deamon线程,如果是,则通知DestroyJavaVM 线程卸载JVM。

ps:

扩展一下:

1.如果线程退出时判断自己不为最后一个非deamon线程,那么调用thread->exit(false) ,并在其中抛出thread_end事件,jvm不退出。

2.如果线程退出时判断自己为最后一个非deamon线程,那么调用before_exit() 方法,抛出两个事件:  事件1:thread_end 线程结束事件、事件2:VM的death事件。

    然后调用thread->exit(true) 方法,接下来把线程从active list卸下,删除线程等等一系列工作执行完成后,则通知正在等待的DestroyJavaVM 线程执行卸载JVM操作。

ContainerBackgroundProcessor 线程 JBOSS 它是一个守护线程, 在jboss服务器在启动的时候就初始化了,主要工作是定期去检查有没有Session过期.过期则清除.

参考:http://liudeh-009.iteye.com/blog/1584876

Dispatcher-Thread-3  线程 Log4j  Log4j具有异步打印日志的功能,需要异步打印日志的Appender都需要注册到 AsyncAppender对象里面去,由AsyncAppender进行监听,决定何时触发日志打印操作。 AsyncAppender如果监听到它管辖范围内的Appender有打印日志的操作,则给这个Appender生成一个相应的event,并将该event保存在一个buffuer区域内。  Dispatcher-Thread-3线程负责判断这个event缓存区是否已经满了,如果已经满了,则将缓存区内的所有event分发到Appender容器里面去,那些注册上来的Appender收到自己的event后,则开始处理自己的日志打印工作。 Dispatcher-Thread-3线程是一个守护线程。

Finalizer线程 JVM 这个线程也是在main线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的finalize()方法;关于Finalizer线程的几点:

  1) 只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行;

  2) 该线程也是daemon线程,因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法,JVM也会退出;

  3) JVM在垃圾收集时会将失去引用的对象包装成Finalizer对象(Reference的实现),并放入ReferenceQueue,由Finalizer线程来处理;最后将该Finalizer对象的引用置为null,由垃圾收集器来回收;

  4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做,很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难;

Gang worker#0 JVM JVM 用于做新生代垃圾回收(monir gc)的一个线程。#号后面是线程编号,例如:Gang worker#1

GC Daemon JVM GC Daemon 线程是JVM为RMI提供远程分布式GC使用的,GC Daemon线程里面会主动调用System.gc()方法,对服务器进行Full GC。 其初衷是当 RMI 服务器返回一个对象到其客户机(远程方法的调用方)时,其跟踪远程对象在客户机中的使用。当再没有更多的对客户机上远程对象的引用时,或者如果引用的“租借”过期并且没有更新,服务器将垃圾回收远程对象。

不过,我们现在jvm启动参数都加上了-XX: DisableExplicitGC配置,所以,这个线程只有打酱油的份了。

IdleRemover JBOSS Jboss连接池有一个最小值, 该线程每过一段时间都会被Jboss唤起,用于检查和销毁连接池中空闲和无效的连接,直到剩余的连接数小于等于它的最小值。

Java2D Disposer JVM  这个线程主要服务于awt的各个组件。 说起该线程的主要工作职责前,需要先介绍一下Disposer类是干嘛的。 Disposer提供一个addRecord方法。 如果你想在一个对象被销毁前再做一些善后工作,那么,你可以调用Disposer#addRecord方法,将这个对象和一个自定义的DisposerRecord接口实现类,一起传入进去,进行注册。 

          Disposer类会唤起“Java2D Disposer”线程,该线程会扫描已注册的这些对象是否要被回收了,如果是,则调用该对象对应的DisposerRecord实现类里面的dispose方法。

          Disposer实际上不限于在awt应用场景,只是awt里面的很多组件需要访问很多操作系统资源,所以,这些组件在被回收时,需要先释放这些资源。

InsttoolCacheScheduler_

QuartzSchedulerThread Quartz  InsttoolCacheScheduler_QuartzSchedulerThread是Quartz的主线程,它主要负责实时的获取下一个时间点要触发的触发器,然后执行触发器相关联的作业 。

        原理大致如下:

        Spring和Quartz结合使用的场景下,Spring IOC容器初始化时会创建并初始化Quartz线程池(TreadPool),并启动它。刚启动时线程池中每个线程都处于等待状态,等待外界给他分配Runnable(持有作业对象的线程)。

        继而接着初始化并启动Quartz的主线程(InsttoolCacheScheduler_QuartzSchedulerThread),该线程自启动后就会处于等待状态。等待外界给出工作信号之后,该主线程的run方法才实质上开始工作。run中会获取JobStore中下一次要触发的作业,拿到之后会一直等待到该作业的真正触发时间,然后将该作业包装成一个JobRunShell对象(该对象实现了Runnable接口,其实看是上面TreadPool中等待外界分配给他的Runnable),然后将刚创建的JobRunShell交给线程池,由线程池负责执行作业。

线程池收到Runnable后,从线程池一个线程启动Runnable,反射调用JobRunShell中的run方法,run方法执行完成之后, TreadPool将该线程回收至空闲线程中。

InsttoolCacheScheduler_Worker-2 Quartz InsttoolCacheScheduler_Worker-2线程就是ThreadPool线程的一个简单实现,它主要负责分配线程资源去执行

InsttoolCacheScheduler_QuartzSchedulerThread线程交给它的调度任务(也就是JobRunShell)。

JBossLifeThread Jboss    Jboss主线程启动成功,应用程序部署完毕之后将JBossLifeThread线程实例化并且start,JBossLifeThread线程启动成功之后就处于等待状态,以保持Jboss Java进程处于存活中。  所得比较通俗一点,就是Jboss启动流程执行完毕之后,为什么没有结束? 就是因为有这个线程hold主了它。 牛b吧~~

JBoss System Threads(1)-1 Jboss   该线程是一个socket服务,默认端口号为: 1099。 主要用于接收外部naming service(Jboss  JNDI)请求。

JCA PoolFiller Jboss     该线程主要为JBoss内部提供连接池的托管。  简单介绍一下工作原理 :

    Jboss内部凡是有远程连接需求的类,都需要实现ManagedConnectionFactory接口,例如需要做JDBC连接的

XAManagedConnectionFactory对象,就实现了该接口。然后将XAManagedConnectionFactory对象,还有其它信息一起包装到InternalManagedConnectionPool对象里面,接着将InternalManagedConnectionPool交给PoolFiller对象里面的列队进行管理。  JCA PoolFiller线程会定期判断列队内是否有需要创建和管理的InternalManagedConnectionPool对象,如果有的话,则调用该对象的fillToMin方法, 触发它去创建相应的远程连接,并且将这个连接维护到它相应的连接池里面去。

JDWP Event Helper Thread JVM           

JDWP是通讯交互协议,它定义了调试器和被调试程序之间传递信息的格式。它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的JVMTI和JDI的通信通畅。  该线程主要负责将JDI事件映射成JVMTI信号,以达到调试过程中操作JVM的目的。 

JDWP Transport Listener: dt_socket JVM 该线程是一个Java Debugger的监听器线程,负责受理客户端的debug请求。 通常我们习惯将它的监听端口设置为8787。

Low Memory Detector JVM 这个线程是负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间。

process reaper JVM     该线程负责去执行一个 OS 命令行的操作。

Reference Handler JVM         JVM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题 。

Surrogate Locker Thread (CMS) JVM          这个线程主要用于配合CMS垃圾回收器使用,它是一个守护线程,其主要负责处理GC过程中,Java层的Reference(指软引用、弱引用等等)与jvm 内部层面的对象状态同步。 这里对它们的实现稍微做一下介绍:这里拿 WeakHashMap做例子,将一些关键点先列出来(我们后面会将这些关键点全部串起来):

1.  我们知道HashMap用Entry[]数组来存储数据的,WeakHashMap也不例外, 内部有一个Entry[]数组。

2.  WeakHashMap的Entry比较特殊,它的继承体系结构为Entry->WeakReference->Reference 。

3.  Reference 里面有一个全局锁对象:Lock,它也被称为pending_lock.    注意:它是静态对象。

4.  Reference  里面有一个静态变量:pending。

5.  Reference  里面有一个静态内部类:ReferenceHandler的线程,它在static块里面被初始化并且启动,启动完成后处于wait状态,它在一个Lock同步锁模块中等待。

6.  另外,WeakHashMap里面还实例化了一个ReferenceQueue列队,这个列队的作用,后面会提到。

7.  上面关键点就介绍完毕了,下面我们把他们串起来。

   

编辑:计算机教程 本文来源:Java多线程:死锁,java多线程

关键词: