JAVA线程与异常处理
Java有两个机制:多线程(Multithread)和异常处理(Exception)。本章前半部分是关于Thread这一基本类以及一套先进的同步原语的介绍,它们使得利用Java编写多线程大为方便。在本章的后半部分我们将介绍Java的异常处理机制(Exception),异常处理机制提高了程序的健壮性。另外,本章中间将介绍一个Java的debugger工具Jdb的使用,Jdb工具对于调试多线程程序尤其有好处。
-- execute command each time the program stops
monitor -- list monitors
unmonitor <monitor#> -- delete a monitor
read -- read and execute a command file
lock -- print lock info for an object
threadlocks [thread id] -- print lock info for a thread
disablegc -- prevent garbage collection of an object
enablegc -- permit garbage collection of an object
!! -- repeat last command
-- repeat command n times
help (or ?) -- list commands
version -- print version information
exit (or quit) -- exit debugger
: full class name with package qualifiers or a
pattern with a leading or trailing wildcard ('*').
: thread number as reported in the 'threads' command
: a Java(tm) Programming Language expression.
Most common syntax is supported.
Startup commands can be placed in either "jdb.ini" or ".jdbrc"
in user.home or user.dir
>
利用命令stop in .可以在方法中设置断点,用命令run运行方法。
>stop in Check.main
Breakpoint set Check.main
>run Check
running...
main[1]
Breakpoint hit: Check.main(Chech:18)
main[1] list
14 }
15 }
16 class Check{
17 public static void main(String args[]]){
18 => Son s=new Son();
19 s.speak();
20 }
21 }
main[1]
=>所指的地方即为断点处,然后使用step命令进行步调执行,结果提示断点设置到了类son中用list显示,就可以清楚地看到断点所在位置。
main[1]step
main[1]
Breakpoint hit:Son.(Son:9)
main[1]list
5 void speak(String s){
6 System.out.println("I like "+s+".");
7 }
8 }
9 =>class Son extends Father{
10 void speak(){
11 System.out.println("My father sys:");
12 super.speak();
13 super.speak("hunting");
用cont命令可以继续执行下去,本例十分简单,所以立即给出了运行结果。我们还可以试一试help中显示的其它命令,methods check显示了check类中定义的方法,memory显示了java运行时刻提供的内存等等,用户可以自己去试用一下。
main[1]cont
My father syas:main[1]
I am Father.
I like hunting.
//显示check类中定义的方法
main[1]methods Check
void main(String[])
void ()
//显示java运行时刻提供的内存main[1] memory
Free:295928,total:1777656
//列出线程组
main[1]threadgrouts
1.(java.lang.ThreadGroup)0xe600b8 system
2.(java.lang.ThreadGroup)0xe655e0 main
3.(java.lang.ThreadGroup)0xe8ddd8 Check.main
//列出指定线程组中的线程
main[1]threads system
Group system:
1.(java.lang.Thread)0xe600d0 Frinalizer therad suspended
2.(java.lang.Thread)0xe65570 Debugger agent running
3.(sun.tools.debug.BreakpointHandler)0xe8b080 Breakpoint handler cond. waitin
Group main:
4.(java.lang.Thread)0xe600a8 main suspended
Group Check.main:
事实上,Jdb工具现在还存在不少缺陷正待改进,使用时有时会出现一些莫名其妙的错误,所以使用时请大家最好联网,便于查询。
5.1 多线程(Multithread)
5.1.1 线程的基本概念 在介绍多线程之前,我们先来了解一些相关的基本概念。一般来说,我们把程序的一次执行称为进程(process)。一个进程包括一个程序模块和该模块一次执行时所处理的数据。每个进程与其它进程拥有不同的数据块,其内存地址是分开的。进程之间的通信要通过寻址,一般需使用信号、管道等进行通信。线程(thread)是指进程内部一段可独立执行的有独立控制流的指令序列。子线程与其父线程共享一个地址空间,同一个任务中的不同线程共享任务的各项资源。 多进程与多线程是多任务的两种类型。以前的操作系统,如Win31,只运行多进程,而Win95及WinNT则支持多线程与多进程。Java通过提供Package类(Java.lang.package)支持多进程,而提供Thread类来支持多线程。 多线程与多进程的主要区别在于,线程是一个进程中一段独立的控制流,一个进程可以拥有若干个线程。在多进程设计中各个进程之间的数据块是相互独立的,一般彼此不影响,要通过信号、管道等进行交流。而在多线程设计中,各个线程不一定独立,同一任务中的各个线程共享程序段、数据段等资源,如图5.1。 正如字面上所表述的那样,多线程就是同时有多个线程在执行。在多CPU的计算机中,多线程的实现是真正的物理上的同时执行。而对于单CPU的计算机而言,实现的只是逻辑上的同时执行。在每个时刻,真正执行的只有一个线程,由操作系统进行线程管理调度,但由于CPU 的速度很快,让人感到像是多个线程在同时执行。 多线程比多进程更方便于共享资源,而Java又提供了一套先进的同步原语解决线程之间的同步问题,使得多线程设计更易发挥作用。用Java设计动画以及设计多媒体应用实例时会广泛地使用到多线程,在后面几章你将看到多线程的巨大作用,当然,现在必须先学习一些多线程的基本知识,慢慢地你就体会到它的优越性。 5.1.2 线程的状态 如同进程有等待、运行、就绪等状态一样,线程也有其状态。 当一个线程通过new被创建但还未运行时,称此线程处于准备状态(new状态)。当线程调用了start()方法或执行run()方法后,则线程处于可运行状态。若在等待与其它线程共享资源,则称线程处于等待状态。线程的另一个状态称为不可运行(not runnable)状态,此时线程不仅等分享处理器资源,而且在等待某个能使它返回可运行状态的事件,例如被方法suspend()挂起的进程就要等待方法resume()方可被唤醒。当调用了stop()方法或线程执行完毕,则线程进入死亡(dead)状态。线程的各个状态之间的转换关系见图5.2。 5.1.3 创建线程 在了解基本概念后,下面学习如何在Java中创建多线程。 Java通过java.lang.Thread类来支持多线程。在Thread类中封装了独立的有关线程执行的数据和方法,并将多线程与面向对象的结构合为一体。 Java提供了两种方法创建线程,一种是继承Thread类,另一种则是实现接口Runnable。 1.继承Thread类 通过继承Thread类创建线程十分简单,只需要重载run()方法提供执行入口就可以,下面我们通过例5.1来解释说明。 例5.1 ThreadTest1.java。- import java.lang.Thread;
- import java.lang.System;
- import java.lang.Math;
- import java.lang.InterruptedException;
- class ThreadTest1{
- public static void main(String args[])
- throws java.io.IOException{
- System.out.println("If want to show the result,press return");
- MyThread thread1=new MyThread("thread1");
- MyThread thread1=new MyThread("thread2");//创建了两个线程thread1和thread2
- thread1.start();//开始执行线程
- thread2.start();
- char ch;
- while((ch=(char)System.in.read()) != ' ');//不断循环,等待输入回车符
- thread1.tStart();//改变thread1和thread2中的循环控制变量的值
- thread2.tStart();//以下部分保证main()方法是最后一个结束的
- while((thread1.isAlive())|(thread2.isAlive()));
- /*{
- you can do anything that you want to do here.
- }
- */
- System.out.println("The test is end.");
- }
- }
- //类MyThread继承了类Thread
- class MyThread extends Thread{
- private boolean keepRunning=true;
- public MyThread(String id){//类MyThread的构造方法
- super(id);
- }
- void randomWait(){//让线程处于等待状态
- try{
- sleep((long)(3000*Math.random()));
- }
- catch(InterruptedException x){
- System.out.println("Interrupted!");
- }
- }
- public void tStart(){
- keepRunning=false;
- }
- public void run(){//重写了类Thread中的方法run(),main()中调用Thread的方法start()后将自动调用此方法
- int i=0;
- while(keepRunning) i++;//i代表循环次数
- //输出结果
- for(int j=0;j<=3;i++){
- randomWait();
- System.out.println("I am"+getName()+"—— I have run"+i+"times.");
- i++;
- }
- System.out.println(getName()+" is dead!");
- }
- }
- import java.lang.Thread;
- import java.lang.System;
- import java.lang.Math;
- import java.lang.InterruptedException;
- import java.lang.Runnable;
- class ThreadTest2{
- public static void main(String args[])
- throws java.io.IOException{
- System.out.println("If want to show the result,press return");//创建了两个MyClass类的对象//class1和class2,MyClass类实现了接口Runnable
- MyClass class1 = new MyClass("thread1");
- MyClass class2 = new MyClass("thread2");//创建了两个MyClass类的对象class1和class2,MyClass类实现了接口Runnable
- Thread thread1=new Thread(class1);
- Thread thread2=new Thread(class2);//将对象class1和class2作为参数传给Thread类的构造函数,创建了两个线程thread1和thread2。
- thread1.start();//开始执行线程
- thread2.start();
- char ch;
- while((ch=(char)System.in.read()) != ' ');//不断循环,等待输入回车符
- class1.tStart();//改变thread1和thread2中的循环控制变量的值
- class2.tStart();//以下部分保证main()方法是最后一个结束的
- while((thread1.isAlive())||(thread2.isAlive()));
- /*{
- you can do anything that you want to do here.
- }
- */
- System.out.println("The test is end.");
- }
- }
- //类MyClass实现了接口Runnable
- class MyClass implements Runnable{
- boolean keepRunning=true;
- String name;
- public MyClass(String id){//类MyClass的构造方法
- name=id;
- }
- void randomWait(){//让线程处于等待状态
- try{
- Thread.currentThread().sleep((long)(3000*Math.random()));//注意:接口Runnable中没有方法sleep(),所以必须先调用Thread的类方法currentThread()来获取一个Thread的对象,然后再调用方法seleep()
- }
- catch(InterruptedException x){
- System.out.println("Interrupted!");
- }
- }
- public void tStart(){
- keepRunning=false;
- }
- public void run(){//与程序ThreadTest1.java类似
- int i=0;
- while(keepRunning) i++;//i代表循环次数
- //输出结果
- for(int j=0;j<=3;j++){
- randomWait();
- System.out.println("I am "+name+"—— I have run "+i+" times.");
- i++;
- }
- System.out.println(name+" is dead!");
- }
- }
5.2 Debugger的使用
至此我们已经书写了不少程序,大家可能发觉出错要调试很困难,其实java工具包中的Java debugger为用户提供了方便的调试机制。虽然jdb的界面不是很漂亮,但很有用,尤其对于调试多线程程序。 Java的debugger需要jdb命令激活。如下执行: C:>jdb 在执行之前,请用带-g参数的javac对程序进行编译,本节我们使用了前一章中check.java,第一步先重新编译方法如下: C:synetjavajavaexmples>javac -g check.java 用下面的方法可以进入jdb,可以直接在jdb后紧接要调试的类名,也可缺省,在进入jdb后利用load载入要调试的类。 C:MyDemodawn>jdb Check Initializing jdb... 0xe8d370:class(Check) 在Check这一类名前的16进制数是Check类在Java运行时的标识。 进入了jdb后,可以使用help来获取所需的使用信息: > help ** command list ** run [class [args]] -- start execution of application's main class threads [threadgroup] -- list threads thread -- set default thread suspend [thread id(s)] -- suspend threads (default: all) resume [thread id(s)] -- resume threads (default: all) where [thread id] | all -- dump a thread's stack wherei [thread id] | all -- dump a thread's stack, with pc info up [n frames] -- move up a thread's stack down [n frames] -- move down a thread's stack kill -- kill a thread with the given exception object interrupt -- interrupt a thread print -- print value of expression dump -- print all object information eval -- evaluate expression (same as print) set = -- assign new value to field/variable/array element locals -- print all local variables in current stack frame classes -- list currently known classes class -- show details of named class methods -- list a class's methods fields -- list a class's fields threadgroups -- list threadgroups threadgroup -- set current threadgroup stop in .[(argument_type,...)] -- set a breakpoint in a method stop at : -- set a breakpoint at a line clear .[(argument_type,...)] -- clear a breakpoint in a method clear : -- clear a breakpoint at a line clear -- list breakpoints catch -- break when specified exception thrown ignore -- cancel 'catch' for the specified exception watch [access|all] . -- watch access/modifications to a field unwatch [access|all] . -- discontinue watching access/modifications to a field trace methods [thread] -- trace method entry and exit untrace methods [thread] -- stop tracing method entry and exit step -- execute current line step up -- execute until the current method returns to its cal ler stepi -- execute current instruction next -- step one line (step OVER calls) cont -- continue execution from breakpoint list [line number|method] -- print source code use (or sourcepath) [source file path] -- display or change the source path exclude [class id ... | "none"] -- do not report step or method events for specified classes classpath -- print classpath info from target VM monitor最新内容
- Linux系统下systemctl常用命令以及service文件配置
- CI PHP7 session 不能读取的问题
- centos 7.4 基本配置
- mysqldump导入导出数据库总结
- Linux下的tar压缩解压缩常用命令
- 查看 SELinux状态、临时关闭SELinux、永久关闭SELinux
- centos6.8 yum安装mysql 5.6
- CentOS之7与6的区别2
- CentOS之7与6的区别1
- Mysql 忘记root密码的完美解决方法
- 输入密码登录,Linux scp (rsync)设置nohup后台运行
- ubantu zabbix部署——安装配置zabbix agent详解
- Zabbix客户端(agent端口)安装配置
- CentOS 7添加开机启动服务/脚本
- 阿里云机器配置 centos 6.8