• Jconsole: JAVA 监视和管理控制台简介


    ###Jconsole: JAVA 监视和管理控制台简介 JDK中除了提供大量的命令行之外,还提供两个功能强大的可视化工具:JConsole和VisualVM。 之前对java的调试一直停留在 右键->debug as ,实在惭愧,今天看了下,索性当个读书笔记记录,果然我JAVA大法好,hhh......

    启动JConsole

    通过D:Program FilesJavajdk1.7.0_71in找到jconsole.exe启动,这个位置取决于本机安装的java路径。类似jps命令,显示本机运行的所有虚拟机进程。可支持本地进程和远程进程。

    双击选择一个进程,看到如下:

    “概述”显示整个虚拟机主要运行数据的概览,其中包括“堆内存使用情况”、“线程”、“类”、“CPU使用情况”4中信息的曲线图,这些曲线图是后面“内存”、“线程”、“类”页签的信息汇总。

    内存监控

    相当于可视化的jstat命令,用于监视受收集器管理的虚拟机内存(JAVA堆和永久代)的变化趋势。

    线程监控

    相当于可视化jstack命令,遇到线程停顿时可是用这个页签进行监控分析。而jstack命令中 线程长时间停顿的主要原因有:
    等待外部资源(数据库连接,网络资源,设备资源等)
    死循环
    锁等待(活锁和死锁)

    通过例子进行说明:
    代码如下:

    package com.xjtu.imiss.chapter4;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public class MonitoringTest {
    
    	/**
    	 * 线程死循环演示
    	 */
    	public static void createBusyThread() {
    		Thread thread = new Thread(new Runnable() {
    			@Override
    			public void run() {
    				while (true);// 第15行
    			}
    		}, "testBusyThread");
    		thread.start();
    	}
    
    	/**
    	 * 线程锁等待演示
    	 */
    	public static void createLockThread(final Object lock) {
    		Thread thread = new Thread(new Runnable() {
    			@Override
    			public void run() {
    				synchronized (lock) {
    					try {
    						lock.wait();
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}, "testLockThread");
    		thread.start();
    	}
    
    	public static void main(String[] args) throws Exception {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		br.readLine();
    		createBusyThread();
    		br.readLine();
    		Object obj = new Object();
    		createLockThread(obj);
    	}
    }
    

    程序运行后,首先在“线程”页签选择main线程,如下所示:

    堆栈追踪显示BufferedReader在readBytes方法中等待System.in的键盘输入,这时线程为Runnable状态,Runnable状态的线程会被分配运行时间,但readBytes方法检查到流没有更新时候就会归还执行令牌,这种等待只消耗很小的CPU资源。

    下来看testBusyThread线程,一直执行空循环,从状态中看到代码停留在while(true)这一行,此时线程为Runnable装啊提,而且没有归还线程令牌的动作会在空循环用尽全部执行时间,直到线程切换,这种等待比较消耗CPU资源。

    下来是testLockThread线程等到这lock对象的notify 或者notifyAll方法的出现,此时线程处于waiting状态,在被唤醒之前不会被分配执行时间。

    testLockThread处于正常的活锁等待,只要lock对象的notify()或者notifyAll()方法被调用,这个线程就能激活并继续执行。下面演示一个无法再被激活的死锁等待。

    package com.xjtu.imiss.chapter4;
    
    public class MonitoringTest {
    	/**
    	 * 线程死锁等待演示
    	 */
    	static class SynAddRunalbe implements Runnable {
    		int a, b;
    
    		public SynAddRunalbe(int a, int b) {
    			this.a = a;
    			this.b = b;
    		}
    
    		@Override
    		public void run() {
    			synchronized (Integer.valueOf(a)) {
    				synchronized (Integer.valueOf(b)) {
    					System.out.println(a + b);
    				}
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		for (int i = 0; i < 100; i++) {
    			new Thread(new SynAddRunalbe(1, 2)).start();
    			new Thread(new SynAddRunalbe(2, 1)).start();
    		}
    	}
    
    }
    

    这段代码开了200个线程分别计算1+2以及2+1的值,其实for循环可省略,因为两个线程也能导致死锁,不过那样概率很小,需要尝试运行多词才能看到效果。一般的话,带for循环的版本最多运行2~3次就会遇到线程死锁,程序无法结束。造成死锁的原因是Integer.valueOf()方法基于减少对象创建和节省内存的考虑,[-128,127]之间的数字会被缓存,当valueOf()方法传入参数在这个范围内,将直接返回缓存中的对象。也就是说,代码调用了200次Integer.valueOf()一共就返回两个不同的对象。

    假如在某个线程的synchronized块之间发生了一次线程切换,那就会出现线程A等待线程B持有的Integer.valueOf(1),线程B又等待线程A持有的Integer.valueOf(2),结果大家都跑不下去了。


    点击“检测到死锁”,查看结果如下:

    主要参考深入理解JAVA虚拟机 jvm高级特性和最佳实践这本书,感谢作者~多谢大牛~~~

  • 相关阅读:
    Java中,由this关键字引发的问题
    Spring3.2.11与Quartz2.2.1整合时内存泄漏的问题的解决
    使用Nexus管理Maven仓库时,上传带依赖的第三方jar
    ActiveMQ5.10.2版本配置JMX
    JAVA的Hashtable在遍历时的迭代器线程问题
    关于JAVA中String类型的最大长度
    新增了某个模组后VS编译不过,报错说找不到头文件
    重写Overlap事件
    cmd端口占用查看和关闭端口
    转---详细的Android开发环境搭建教程
  • 原文地址:https://www.cnblogs.com/tina-smile/p/5327057.html
Copyright © 2020-2023  润新知