使用visual vm 分析线程(上)

网上很多visual vm的指南手册之类,visual vm最新的下载好后,直接运行即可。

如果无法运行,在右键选择要执行的类,选择Run As-->Open Run Dialog,在新窗口中选择Arguments标签。

vm参数上增加:-XX:+PerfBypassFileSystemCheck

 

 

【代码背景介绍——4个线程】

客户端向我的Server中发送消息,我的代码中有一个正常消息List infoList,一个异常的消息List errList。对于这两个List,都各自有一个监听线程,监听到了List中有数据,则发送出去,无数据则休眠。

同时为了防止数据丢失,每个数据在进入这两个List前都要写入文件系统。当数据发送成功后,则将正常发送数据写入待删除的infoDelList,异常重发的数据写入errDelList。因此又增加了infoDelList和errDelList监听,当这两个List有数据,则遍历这并删除文件系统的数据。

因此我有4个线程监听这4个List。

 

【开始测试】

第一次测试。

先启动服务器,1分钟内无客户端发送的数据,那么此时4个监听线程都在休眠。

1分钟后,客户端开始每一秒钟并发20个,总共5000个数据。

这次我让所有的客户端数据全部可以发送成功。那么通过visual vm可以看到2个监听应该一直在休眠的。如图:

 

解释:

【0:00-1:00】:可以看到有4个线程在有并发数据前都在紫色的休眠状态。

【1:00-2:00】:当并发开始后,Thread-0和Thread-2一直在Sleeping上的紫色状态有些开始有绿色的Running的时间片了。在1分18秒时刻,Thread-2线程正在执行,Thread-0线程在该时刻是红色的监视状态。表示Thread-2想执行synchronized中的代码,但是没有锁,进入堵塞等待了,可以看到在1分35秒左右Thread-2获得时间片执行了。

 

说了半天的Thread-1,Thread-2,怎么知道他们对应的代码是哪个呢?visual vm中显示的名字其实就是线程的名字。可以通过打印日志,查看代码中个线程和visual vm的线程名字对应。如下在run方法中,进入循环之前打印前获取线程名字:Thread.currentThread().getName(),下面这个线程打印出来是Thread-0 。

 

 

Java代码   收藏代码
  1. import java.io.File;  
  2. import java.util.List;  
  3. import org.apache.log4j.Logger;  
  4.   
  5. /** 
  6.  * 消息中心磁盘文件删除监听 
  7.  * @author zhuoyueping 
  8.  * 
  9.  */  
  10. public class DiskDeleteListener extends Thread{  
  11.     public static  List pathList =  null;  
  12.     private static final Logger log = Logger.getLogger(DiskDeleteListener.class);  
  13.     private static DiskDeleteListener instance = new DiskDeleteListener();  
  14.     private DiskDeleteListener(){  
  15.         super();  
  16.     }  
  17.     public static DiskDeleteListener getInstance(){  
  18.         return instance;  
  19.     }  
  20.     public void run() {  
  21.         log.info("Thread Name="+Thread.currentThread().getName());  
  22.             while(true){{  
  23.                 try {  
  24.                     if(DiskDeleteListener.pathList!=null&&DiskDeleteListener.pathList.size()>0){  
  25.                         for(int i = 0;i<DiskDeleteListener.pathList.size();){  
  26.                             String path = (String) DiskDeleteListener.pathList.get(i);  
  27.                             if(path!=null){  
  28.                                 File file = new File(path);  
  29.                                 if(file.exists()){  
  30.                                     //删除文件  
  31.                                     file.delete();  
  32.                                     DiskDeleteListener.pathList.remove(i);  
  33.                                 }else{  
  34.                                     DiskDeleteListener.pathList.remove(i);  
  35.                                     log.error("第"+i+"个,"+"文件不存在,清理内存数据完成"+path);  
  36.                                 }  
  37.                             }else{  
  38.                                 DiskDeleteListener.pathList.remove(i);  
  39.                             }  
  40.                         }  
  41.                     }  
  42.                     Thread.sleep(1000);  
  43.                 } catch (InterruptedException e) {  
  44.                     e.printStackTrace();  
  45.                     log.error(e);  
  46.                 }  
  47.             }  
  48.         }  
  49.     }  
  50. }  

如果覆盖start方法,在start方法中去取Thread.currentThread().getName(),将得到main,即启动该线程的线程名。因此Thread.currentThread()一定是在run中的线程,一个线程的start被执行时候,Thread.currentThread()获得的是它的父线程。

 

 

Thread-0,用于删除已经发送成功的消息的磁盘文件;而跟它竞争的Thread-2则是监听待发送的infoList。

多次在同一个时刻,thread-0是红色的堵塞,threa-2在执行,看起来像是他们在竞争同一资源。查代码可以看到,这两个线程都会对DiskDeleteListener.pathList进行读写操作,thread-0监听到list不为空则删除磁盘文件,threa-2发送一个消息成功,则将消息的磁盘地址加入到list中。而这个pathList是一个线程安全的List,通过下面的方法构造出来的:

 

Java代码   收藏代码
  1. DiskDeleteListener.pathList = Collections.synchronizedList(new ArrayList());  

 

最后异常消息发送和异常磁盘监听的两个线程一直处于休眠状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值