- 浏览: 38347 次
- 性别:
- 来自: 杭州
最新评论
-
Bruce_Tender:
非常感谢楼主分享
虚拟机stack全分析 -
carlosfu:
非常好,收获很大,很赞。
虚拟机stack全分析 -
huoyanxueren:
半成品,需要自己结合各种组件去搭建,类似于wordpress。 ...
博客迁移到www.itcamel.com -
ForeverCjl:
你那个博客是自己写的还是用的开源现成的?
博客迁移到www.itcamel.com
通过jps -lv 获取到本地的一个JVM实例进程。再通过jstack pid > thread.txt ,把stack trace输出到thread.txt文件中。
2012-08-28 23:16:39
2012-08-28 23:16:39 Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing): "Attach Listener" daemon prio=10 tid=0xb3da5400 nid=0x13ea waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188) - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool) at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50) "Worker-12" prio=10 tid=0x09910c00 nid=0x12a0 in Object.wait() [0xb4026000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188) - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool) at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50) .......省略 "Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000] java.lang.Thread.State: RUNNABLE "CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=10 tid=0x097e7400 nid=0xa9d runnable [0x00000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=10 tid=0x097e4000 nid=0xa9c in Object.wait() [0xb4dd1000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133) - locked <0x6e2e02f8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177) "Reference Handler" daemon prio=10 tid=0x097df400 nid=0xa9b in Object.wait() [0xb4e22000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) - locked <0x6e2e0098> (a java.lang.ref.Reference$Lock) "main" prio=10 tid=0x097b0400 nid=0xa99 runnable [0xbf8b9000] java.lang.Thread.State: RUNNABLE at org.eclipse.swt.internal.gtk.OS.Call(Native Method) at org.eclipse.swt.widgets.Display.sleep(Display.java:4069) at org.eclipse.ui.application.WorkbenchAdvisor.eventLoopIdle(WorkbenchAdvisor.java:364) at org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor.eventLoopIdle(IDEWorkbenchAdvisor.java:917) at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2697) at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2660) at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494) at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674) at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149) at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:123) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:616) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577) at org.eclipse.equinox.launcher.Main.run(Main.java:1410) "VM Thread" prio=10 tid=0x097dd800 nid=0xa9a runnable "GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable "GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable "VM Periodic Task Thread" prio=10 tid=0x097ed400 nid=0xaa0 waiting on condition JNI global references: 2131
上面的stack trace一共可以拆解成5个部分。
第一部分: Full thread dump identifier
2012-08-28 23:16:39 Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing):
可以看到dump时间,虚拟机的信息。
第二部分: Java EE middleware, third party & custom application Threads
"Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188) - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool) at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
此处是我们最为关心的地方,也是通过stack trace查找问题的地方,每个item的具体含义是
-Thread name: "Worker-15"
-线程优先级: prio=10
-java线程的identifier:tid=0x09b7b400
-native线程的identifier: nid=0x12f2
-线程的状态: in Object.wait() java.lang.Thread.State: TIMED_WAITING (on object monitor)
-线程栈起始地址:[0xb30f9000]
Java线程和Native线程,也就是tid和nid的区别?
VM是加载并执行字节码的机器,这个处理不对应具体硬件,它完全由软件来实现。虚拟机并不是直接跑在宿主的cpu上,中间还隔着宿主的操作系统。
虚拟机的职责是:翻译字节码,把它翻译成一系列的动作(内存操作)和系统调用(比如输入输出)。举个例子:当在java里请求与某台远程机器建立socket连接时,java虚拟机本身是不能完成这一工作的(协议栈是在操作系统内实现的),所以它需要系统调用。要明白这个,还需要知道JRE和JVM的关系。JRE是JVM的环境,一个应用程序就是一个JVM实例。一个机器上一般同时只有一个JRE环境,但是可以同时有多个JVM实例。不同的操作系统和CPU架构有不同的JRE。JRE包含了最基本的类库,当然包括和操作系统打交道的Native库,比如windows下的dll文件,linux下的so文件。JVM实例解析字节码的成JVM中的指令集,再通过Native方法进行操作系统层面的系统调用。下面的图能比较清楚的说明问题。
JVM线程如何创建
当然是通过Native库的 native方法。JVM的线程最终是通过操作系统的线程来完成系统调用的。针对Java开发者来说,发号施令的是JVM 线程,具体干藏活累活的却是操作系统线程。不同操作系统上,JVM创建本地线程依赖的native库也不同。具体可参考下面的的文章。http://jackyhongvip.iteye.com/blog/1338610
JVM线程状态
状态有Runnable、Wait on condition、Waiting for monitor entry 和 in Object.wait()。
Runnable:不解释
Wait on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写。如果网络数据没准备好,线程就等待在那里。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
Waiting for monitor entry 和 in Object.wait():这两种情况在多线程的情况下经常出现。Java是通过Monitor来实现线程互斥和协作(有些把Monitor直译成锁,我认为不妥,不是还有Lock嘛)。具体Monitor的深入理解见 http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html
但是可以理解成Monitor是一个对象或者class所拥有的锁,每个对象和class有且仅有一个。见下图.
每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。
在 “ Entry Set”里面的线程都等待拿到Monitor,拿到了线程就成为了Runnable线程,否则就会一直处于处于 “waiting for monitor entry”。一段代码作为例子
public class MyThread implements Runnable{ public void run() { synchronized(this) { for (int i = 0; i < 1; i--) { System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); } } } public static void main(String[] args) { MyThread t1 = new MyThread(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } }
大家一看就知道,B线程肯定是“千年老二“,永远拿不到Monitor了。
对应的stack:
"B" prio=10 tid=0x0969a000 nid=0x11d6 waiting for monitor entry [0x8bb22000] java.lang.Thread.State: BLOCKED (on object monitor) at org.marshal.MyThread.run(MyThread.java:7) - waiting to lock <0x94757078> (a org.marshal.MyThread) at java.lang.Thread.run(Thread.java:636) "A" prio=10 tid=0x09698800 nid=0x11d5 runnable [0x8bb73000] java.lang.Thread.State: RUNNABLE at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:297) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) - locked <0x947571b0> (a java.io.BufferedOutputStream) at java.io.PrintStream.write(PrintStream.java:449) - locked <0x94757190> (a java.io.PrintStream) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:220) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:290) at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:103) - locked <0x947572a0> (a java.io.OutputStreamWriter) at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185) at java.io.PrintStream.write(PrintStream.java:494) - locked <0x94757190> (a java.io.PrintStream) at java.io.PrintStream.print(PrintStream.java:636) at java.io.PrintStream.println(PrintStream.java:773) - locked <0x94757190> (a java.io.PrintStream) at org.marshal.MyThread.run(MyThread.java:8) - locked <0x94757078> (a org.marshal.MyThread) at java.lang.Thread.run(Thread.java:636)
<0x94757078> 就是两个线程争夺的Monitor。
在 “Wait Set”里面的线程都如饥似渴地等待拿到Monitor。他们是怎么进入到“Wait Set”的呢?当一个线程拿到了Monitor,但是在其他资源没有到位的情况下,调用同步锁对象(一般是synchronized()内的对象)的 wait() 方法,放弃了 Monitor,它就进入到了 “Wait Set”队列。只有当其他线程通过notify() 或者 notifyAll(),释放了同步锁后,这个线程才会有机会重新去竞争Monitor。在stack中,它表现的状态是in Object.wait()。修改上面的代码public class WaitThread implements Runnable{
public void run() { synchronized(this) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) { WaitThread t1 = new WaitThread(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } }
对应的stack:
"B" prio=10 tid=0x08173000 nid=0x1304 in Object.wait() [0x8baf2000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Object.wait(Object.java:502) at org.marshal.WaitThread.run(WaitThread.java:8) - locked <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Thread.run(Thread.java:636) "A" prio=10 tid=0x08171c00 nid=0x1303 in Object.wait() [0x8bb43000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Object.wait(Object.java:502) at org.marshal.WaitThread.run(WaitThread.java:8) - locked <0xa9cb50e0> (a org.marshal.WaitThread) at java.lang.Thread.run(Thread.java:636)
A和B线程都进入了”wait set“。B线程也拿到过这个Monitor,因为A线程释放过了,这也验证上面的话,他们都在等待得而复失的<0xa9cb50e0>。
基于我们经常讨论到的死锁问题,构造一段代码如下
public class DeadThread implements Runnable{ private Object monitor_A = new Object(); private Object monitor_B = new Object(); public void method_A(){ synchronized(monitor_A) { synchronized(monitor_B) { System.out.println(Thread.currentThread().getName()+" invoke method A"); } } } public void method_B(){ synchronized(monitor_B) { synchronized(monitor_A) { System.out.println(Thread.currentThread().getName()+" invoke method B"); } } } public void run() { for(int i=0;i<1;i--){ method_A(); method_B(); } } public static void main(String[] args) { DeadThread t1 = new DeadThread(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } }
对应的stack:
"B" prio=10 tid=0x0898d000 nid=0x269a waiting for monitor entry [0x8baa2000] java.lang.Thread.State: BLOCKED (on object monitor) at org.marshal.DeadThread.method_A(DeadThread.java:11) - waiting to lock <0xaa4d6f88> (a java.lang.Object) - locked <0xaa4d6f80> (a java.lang.Object) at org.marshal.DeadThread.run(DeadThread.java:28) at java.lang.Thread.run(Thread.java:636) "A" prio=10 tid=0x0898b800 nid=0x2699 waiting for monitor entry [0x8baf3000] java.lang.Thread.State: BLOCKED (on object monitor) at org.marshal.DeadThread.method_B(DeadThread.java:19) - waiting to lock <0xaa4d6f80> (a java.lang.Object) - locked <0xaa4d6f88> (a java.lang.Object) at org.marshal.DeadThread.run(DeadThread.java:29) at java.lang.Thread.run(Thread.java:636)
同时注意到,在stack trace尾部信息
Found one Java-level deadlock: ============================= "B": waiting to lock monitor 0x089615d8 (object 0xaa4d6f88, a java.lang.Object), which is held by "A" "A": waiting to lock monitor 0x08962258 (object 0xaa4d6f80, a java.lang.Object), which is held by "B" Java stack information for the threads listed above: =================================================== "B": at org.marshal.DeadThread.method_A(DeadThread.java:11) - waiting to lock <0xaa4d6f88> (a java.lang.Object) - locked <0xaa4d6f80> (a java.lang.Object) at org.marshal.DeadThread.run(DeadThread.java:28) at java.lang.Thread.run(Thread.java:636) "A": at org.marshal.DeadThread.method_B(DeadThread.java:19) - waiting to lock <0xaa4d6f80> (a java.lang.Object) - locked <0xaa4d6f88> (a java.lang.Object) at org.marshal.DeadThread.run(DeadThread.java:29) at java.lang.Thread.run(Thread.java:636) Found 1 deadlock.
stack中直接报告了Java级别的死锁,够智能吧。
第三部分:HotSpot VM Thread
"Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000] java.lang.Thread.State: RUNNABLE "CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE
JVM管理的内部线程,这些内部线程都是来执行native操作的,可以不必太关注。
第四部分: HotSpot GC Thread
"GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable "GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable
当虚拟机打开了parallel GC,这些线程就会定期地GC清理。
第五部分:JNI global references count
JNI global references: 2131
JNI (Java Native Interface)全局引用也是受垃圾回收器管理。它的作用是防止回收到那些在native代码上还是被引用的,但是在java代码中却没有存活必要的引用。对于防止因为应用代码中直接使用native库或者第三方的一些监控工具的内存泄漏有非常大的帮助。
参考文献:
http://peiliping.ixiezi.com/2012/04/15/jvm-jstack%E7%94%A8%E6%B3%95/
http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html
http://www.javacodegeeks.com/2012/03/jvm-how-to-analyze-thread-dump.html
http://blog.csdn.net/fenglibing/article/details/6411940
发表评论
-
NIO学习全概括
2013-02-26 19:50 1618前言 最近在看java NIO ... -
Zero-copy
2013-02-19 12:26 2114[译] http://en.wikipedia.org/w ... -
Java内省机制
2012-11-24 10:59 0内省 内省是 Java 语言对 Bean 类属性、事件的一种 ... -
Instrument小窥
2012-11-16 19:02 2078java.lang.instrument是java 5开始引 ... -
JVM stack trace全解析
2012-08-31 17:26 34通过jps -lv 获取到本地的一个JVM实例进程。再通过js ... -
jps小记
2012-08-27 22:25 891jps -mlVv localhostjps [ option ... -
jstat小记
2012-08-27 21:58 987jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的 ... -
寻找响应时间最长的线程
2012-08-27 13:51 1001在排查一些load过载和CPU使用过高的情况,我们往往会去排查 ... -
单例模式寻优
2012-05-27 23:15 1209谈到单例模式,目前最 ... -
PMD几个规则小究
2012-03-22 19:00 0111 -
Linux服务器性能小结
2011-10-01 00:01 1919一、服务器性能因素 1、CPU 2、内存 ...
相关推荐
每一个 Java 虚拟机 都有及时生成所有线程在某一点状态的 thread-dump 的能力,虽然各个 Java 虚拟机打印的thread dump 略有不同,但是大多都提供了当前活动线程的快 照,及JVM 中所有 Java线程的堆栈跟踪信息,堆栈...
对于普通程序员,我认为编译原理这门课主要掌握几点就够用了:1. 词法分析方面,掌握正则表达式,了解dfa/nfa。...4. 会实现简单的虚拟机(stack-based,不带GC),并把四则运算表达式翻译为虚拟机指令。
当然,如果您计划向上扩展,您可以根据需要将多个软件组件拆分到更多虚拟机中。 带有 Elastic Stack 和 RSyslog 的 Zimbra 集群示例。 Zimbra 服务器的基本 Kibana 仪表板如下所示: Zimbra 9 安装上的示例 Elastic ...
华为云Stack是位于政企客户本地数据中心的云基础设施,为政企客户提供在云上和本地部署体验一致的云服务。 系列化版本满足传统业务云化,大数据分析与AI训练,建设大规模城市云与行业云等不同业务场景的客户诉求。
大型网站技术架构:核心原理与案例分析 DOCKER技术入门与实战 Docker容器与容器云第2版 NET_CLR_via_C#(第4版) elk-stack-guide-cn Go并发编程实战_第2版_郝林 Go语言学习笔记_雨痕 go-internals-zh steal 图解HTTP+...
逃逸分析 如果对象不会逃逸到方法或线程外,可以做什么优化? Java与C/C++的编译器对比 物理机如何处理并发问题? Java内存模型 什么是Java内存模型? Java内存模型的目标? 主内存与工作内存 内存间的交互操作 原子性、...
第一章 openstack准备工作 - 4 - 第二章 环境预配置 - 16 - 第三章 yum源制作 - 21 - 第四章 keystone - 27 - 第五章 glance安装与配置 - 43 - 第六章 nova服务安装与配置 - 48 - 第七章 neutron安装与配置 - 52 - ...
2、 分别修改三个虚拟机的主机名 3、 主机地址映射配置 4、 禁用selinux 5、 CentOS6本地yum源配置 注:先加载镜像 6、 NTP安装服务 三、 本地源制作 1. Centos6.6本地base、extra源制作 2. 本地base、...
java8虚拟机和之前的变化和更新? 首先JVM由类装载器,运行时数据区域,执行引擎,本地接口库和本地方法库组成。 什么是OOM,什么是栈溢出StackOVerFlowError? 怎么分析 JVM的常用调优参数有哪些 内存快照如何...
早期由原名为"Android"的公司开发,谷歌在2005年收购"Android.Inc"后,继续对Andr oid系统开发运营,它采用了软件堆层(software stack,又名软件叠层)的架构,主要分为三部分。底层Linux内核只提供基本功能,其 ...
│ 高并发编程第一阶段09讲、多线程与JVM内存结构的关系,虚拟机栈实验.mp4 │ 高并发编程第一阶段10讲、Thread构造函数StackSize详细讲解.mp4 │ 高并发编程第一阶段11讲、Thread构造函数StackSize详细讲解-续....
Java虚拟机 4 类加载器 6 Windows环境变量 8 内容总结 13 独立实践 14 第二章: 面向对象概述 15 学习目标 15 面向对象(Object Oriented) 16 面向对象的主要特性 18 抽象(Abstraction) 18 封装(Encapsulation): 19 ...
│ 高并发编程第一阶段09讲、多线程与JVM内存结构的关系,虚拟机栈实验.mp4 │ 高并发编程第一阶段10讲、Thread构造函数StackSize详细讲解.mp4 │ 高并发编程第一阶段11讲、Thread构造函数StackSize详细讲解-续....
7.2.1 IRP与IO_STACK_LOCATION 86 7.2.2 打开与关闭请求的处理 88 7.2.3 应用层信息传入 89 7.2.4 驱动层信息传出 91 探索篇 研究内核 本书的第三部分,开始探索Windows内核程序,并尝试阅读反汇编代码...
7.2.1 IRP与IO_STACK_LOCATION 86 7.2.2 打开与关闭请求的处理 88 7.2.3 应用层信息传入 89 7.2.4 驱动层信息传出 91 探索篇 研究内核 本书的第三部分,开始探索Windows内核程序,并尝试阅读反汇编代码...
7.2.1 IRP与IO_STACK_LOCATION 86 7.2.2 打开与关闭请求的处理 88 7.2.3 应用层信息传入 89 7.2.4 驱动层信息传出 91 探索篇 研究内核 本书的第三部分,开始探索Windows内核程序,并尝试阅读反汇编代码...
11.4.3栈(Stack)使用示例369 11.4.4字典(Dictionary)简介370 11.4.5哈希表(Hashtable)简介371 11.5本章小结371 第12章类型包装器、自动装箱和元数据(注释)372 12.1类型包装器372 12.1.1字符类型包装器...
异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获...
异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的...