java多线程与进程调度_第1页
java多线程与进程调度_第2页
java多线程与进程调度_第3页
java多线程与进程调度_第4页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java多线程与异常处理(2009-02-16 15:18:50)转载标签:分类:JavaitJava 有两个机制: 多线程 (Multithread)和异常处理 (Exception)。本章前半部分是关于Thread 这一基本类以及一套先进的同步原语的介绍,它们使得利用Java 编写多线程大为方便。在本章的后半部分我们将介绍Java 的异常处理机制(Exception),异常处理机制提高了程序的健壮性。另外,本章中间将介绍一个Java 的 debugger 工具 Jdb 的使用, Jdb 工具对于调试多线程程序尤其有好处。5.1多线程 (Multithread)5.1.1线程的基本概念在介绍

2、多线程之前,我们先来了解一些相关的基本概念。一般来说,我们把程序的一次执行称为进程(process)。一个进程包括一个程序模块和该模块一次执行时所处理的数据。每个进程与其它进程拥有不同的数据块,其内存地址是分开的。进程之间的通信要通过寻址,一般需使用信号、管道等进行通信。线程(thread)是指进程内部一段可独立执行的有独立控制流的指令序列。子线程与其父线程共享一个地址空间,同一个任务中的不同线程共享任务的各项资源。多进程与多线程是多任务的两种类型。以前的操作系统,如Win31,只运行多进程,而Win95 及 WinNT则支持多线程与多进程。Java通过提供Package 类 (Java.la

3、ng.package)支持多进程,而提供Thread 类来支持多线程。多线程与多进程的主要区别在于,线程是一个进程中一段独立的控制流,一个进程可以拥有若干个线程。在多进程设计中各个进程之间的数据块是相互独立的,一般彼此不影响,要通过信号、管道等进行交流。而在多线程设计中,各个线程不一定独立,同一任务中的各个线程共享程序段、数据段等资源,如图5.1 。正如字面上所表述的那样,多线程就是同时有多个线程在执行。在多CPU的计算机中,多线程的实现是真正的物理上的同时执行。而对于单CPU的计算机而言,实现的只是逻辑上的同时执行。在每个时刻,真正执行的只有一个线程,由操作系统进行线程管理调度,但由于 CP

4、U 的速度很快,让人感到像是多个线程在同时执行。多线程比多进程更方便于共享资源,而 Java 又提供了一套先进的同步原语解决线程之间的同步问题,使得多线程设计更易发挥作用。用 Java 设计动画以及设计多媒体应用实例时会广泛地使用到多线程,在后面几章你将看到多线程的巨大作用,当然,现在必须先学习一些多线程的基本知识,慢慢地你就体会到它的优越性。5.1.2线程的状态如同进程有等待、运行、就绪等状态一样,线程也有其状态。当一个线程通过new 被创建但还未运行时,称此线程处于准备状态(new 状态 ) 。当线程调用了start()方法或执行run() 方法后,则线程处于可运行状态。若在等待与其它线程

5、共享资源,则称线程处于等待状态。线程的另一个状态称为不可运行(not runnable)状态,此时线程不仅等分享处理器资源,而且在等待某个能使它返回可运行状态的事件,例如被方法suspend() 挂起的进程就要等待方法resume()方可被唤醒。当调用了stop() 方法或线程执行完毕,则线程进入死亡(dead) 状态。线程的各个状态之间的转换关系见图5.2 。5.1.3创建线程在了解基本概念后,下面学习如何在Java 中创建多线程。Java 通过 java.lang.Thread类来支持多线程。在Thread 类中封装了独立的有关线程执行的数据和方法,并将多线程与面向对象的结构合为一体。Ja

6、va 提供了两种方法创建线程,一种是继承Thread 类,另一种则是实现接口Runnable 。1. 继承 Thread 类通过继承Thread 类创建线程十分简单,只需要重载run()方法提供执行入口就可以,下面我们通过例5.1 来解释说明。例 5.1 ThreadTest1.java。1. import java.lang.Thread;2. import java.lang.System;3. import java.lang.Math;4. import java.lang.InterruptedException;5.6. class ThreadTest17. public sta

7、tic void main(String args)8. throws java.io.IOException9. System.out.println(If want to show the result,press return);10. MyThread thread1=new MyThread(thread1);11.MyThread thread1=new MyThread(thread2);/创建了两个线程thread1和 thread212.thread1.start();/开始执行线程13. thread2.start();14. char ch;15.while(ch=(ch

8、ar)System.in.read() != );/不断循环,等待输入回车符16. thread1.tStart();/改变 thread1 和 thread2 中的循环控制变量的值17. thread2.tStart();/以下部分保证 main() 方法是最后一个结束的18. while(thread1.isAlive()|(thread2.isAlive();19.20. System.out.println(The test is end.);21. 22. 23.24. / 类 MyThread 继承了类 Thread25. class MyThread extends Thread

9、26. private boolean keepRunning=true;27.public MyThread(String id)/类 MyThread 的构造方法28. super(id);29. 30.void randomWait()/让线程处于等待状态31. try32. sleep(long)(3000*Math.random();33. 34. catch(InterruptedException x)35. System.out.println(Interrupted!);36. 37. 38. public void tStart()39. keepRunning=false

10、;40. 41.public void run()/重写了类Thread 中的方法run(),main()中调用 Thread 的方法 start()后将自动调用此方法42. int i=0;43.while(keepRunning) i+;/i代表循环次数44. / 输出结果45. for(int j=0;j=3;i+)46. randomWait();47.System.out.println(I am+getName()+ I have run+i+times.);48. i+;49. 50. System.out.println(getName()+ is dead!);51. 52.

11、 53.这个程序中创建了两个线程thread1和 trhrad2 。每个线程将打印一些内容。当线程死亡时,将打印出线程死亡信息。试着执行一下这个程序,你将发现每次的结果都不尽相同。运行结果: ( 略 )下面我们分析一下这个程序。为创建Thread,第一行你必须写import java.lang.Thread。行 625 中书写的类ThreadTest1包含了一个main() 方法 ( 行 724) 。行8 的throws java.io.IOException暗示了main() 方法中可以产生IOException(有关异常处理后面几节将详细介绍) ,这主要是为了调用方法System.in.r

12、ead()实现输入功能。 main()方法中创建了两个MyThread 的对象,即行10 的 thread1与行 11 的 thread2。行 2855 中书写的类MyThread 是 Thread 类的子类。在类MyThread 中重写了方法run()(行 4354) 。在此种构造线程的方法中,这是必须的。行2933 定义了 MyThread 类的构造方法MyThread(String id)。行 32 和行 40 定义了方法randomWait()和 tStart()。在 ThreadTest1 的 main() 方法中,当行 13 调用 thread1.start()与 thread2.

13、start()后,线程 thread1与 thread2进入可运行状态,分别自动执行其run()方法,而 main() 方法也继续执行,此时相当于有三个线程在同时执行。看一下程序,此时thread1与 thread2在执行第4454 行的 run() 方法,为断循环并累计循环次数,而main() 则在等待循环直至入为回车符。 输入回车符, main() 方法结束循环, 继续执行,调用了 MyThread 中方法tStart()(41 43 行) ,这样结束了Thread1 与 Thread2在 run() 方法中的循环,开始执行输出。由于 thread1 , thread2 与 main()

14、三个线程轮流占有 CPU,所以显示了各自结果,这也是为何多次执行结果不同的原因,此时体现了多线程的功能。请注意一下Run() 中调用了 MyThread 类中自定义的方法randomWait()(3340 行 ) 。在 randomWait() 中调用了方法sleep(),sleep()方法是 Thread 类中的方法, 它让正在执行的线程小睡片刻,进入不可运行状态(notrunnable状态 ) ,当时间到时, 线程会回复到runnable状态。当线程执行sleep()时,有可能会被打断,因而程序中加了一段处理InterruptedException的中断处理和打印信息,这样加强了程序的健壮

15、性。另外,人们会注意到,在main() 中有一段循环并未完成什么功能,这是为了简化程序,其实那段时间中你可以做你想完成的任何工作。但请注意,在执行时,最后一个结束的必须是main() 方法,而不可以是其它,否则执行结束将不返回C:提示符,这也是在程序中为何调用了isAlive()方法进行判别的原因。调用类Thread 的 isAlive()方法可以测试线程是否仍在运行状态( 此外指还未死亡) 。至此,你已真正了解了你的第一个关于Thread 的程序,其实Thread 中还有很多方法在此未被使用,后面将会进一步介绍。下面先介绍一下创建Thtead 的另一个方法:利用实现接口Runnable 创建

16、 Thread 。2. 实现接口 Runnable使用用类java.lang.Runnable中的接口Runnable也可创建线程。下面的例子与例5.1 实现的功能相同,只是它利用接口Runnable来实现。例 5.2 ThreadTest2.java。1. import java.lang.Thread;2. import java.lang.System;3. import java.lang.Math;4. import java.lang.InterruptedException;5. import java.lang.Runnable;6.7. class ThreadTest28.

17、 public static void main(String args)9. throws java.io.IOException10.System.out.println(If want to show the result,press return);/创建了两个MyClass 类的对象 /class1和 class2 ,MyClass 类实现了接口Runnable11. MyClass class1 = new MyClass(thread1);12. MyClass class2 = new MyClass(thread2);/创建了两个 MyClass 类的对象 class1 和

18、class2 ,MyClass 类实现了接口Runnable13. Thread thread1=new Thread(class1);14.Thread thread2=new Thread(class2);/将对象 class1和 class2作为参数传给Thread 类的构造函数,创建了两个线程thread1和 thread2 。15.thread1.start();/开始执行线程16. thread2.start();17. char ch;18.while(ch=(char)System.in.read() != );/不断循环,等待输入回车符19. class1.tStart();

19、/改变 thread1 和 thread2 中的循环控制变量的值20. class2.tStart();/以下部分保证 main() 方法是最后一个结束的21. while(thread1.isAlive()|(thread2.isAlive();22.23. System.out.println(The test is end.);24. 25. 26.27. / 类 MyClass 实现了接口 Runnable28. class MyClass implements Runnable29. boolean keepRunning=true;30. String name;31.public

20、 MyClass(String id)/类 MyClass 的构造方法32. name=id;33. 34.void randomWait()/让线程处于等待状态35. try36.Thread.currentThread().sleep(long)(3000*Math.random();/注意: 接口 Runnable 中没有方法 sleep(),所以必须先调用 Thread 的类方法 currentThread()来获取一个 Thread 的对象,然后再调用方法 seleep()37. 38. catch(InterruptedException x)39. System.out.prin

21、tln(Interrupted!);40. 41. 42. public void tStart()43. keepRunning=false;44. 45.public void run()/与程序 ThreadTest1.java类似46. int i=0;47.while(keepRunning) i+;/i代表循环次数48. / 输出结果49. for(int j=0;j=3;j+)50. randomWait();51.System.out.println(I am +name+ I have run +i+ times.);52. i+;53. 54. System.out.pri

22、ntln(name+ is dead!);55. 56. 57.运行结果:( 略 )ThreadTest2创建 thread1与 thread2的方法 (11 14 行 ) 与 ThreadTest1不同, ThreadTest2直接创建了一个 Thread的对象,并将Myclass 的对象作为参数传给Thread 的构造方法。任何实现了Runnable 接口的类的对象都可以作Thread 构造方法的参数。在 main() 方法中,其余部分程序 ThreadTest2与 ThreadTest1.java相同。ThreadTest2的 MyClass 类 (31 59 行) 实现了接口 Runn

23、able ,注意 MyClass 的构造方法实现了name这一类变量,实现run() 时不需要调用 Thread 的方法 getName() ,但在实现 randomWait() 时要使用 Thread.currentThread().Sleep()(39行) ,因为 Runnable 接口并未提供方法 sleep(),因而实现时必须调用Thread 的类方法 currentThread()来调用 sleep()。事实上,无论用继承Thread 的方法或用实现接口Runnable 的方法来实现多线程,在程序书写时区别不大,只需概念清楚略加注意便可。使用继承Thread 类的方法比较简单易懂,实

24、现方便。但如果你创建的Thread 需要是某个其它类的子类时,使用继承Thread 的方法就会出麻烦。比如,实现Applet时,每个 applet 必须是 java.applet.Applet的子类,此时想要实现多线程,只有通过使用Runnable接口,当然,使用 Runnable 接口来实现线程,在书写时会比较麻烦,因为你将不得不多做一些工作才可调用Thread 的方法。3. 线程同步在使用多线程时,由于可以共享资源,有时就会发生冲突。举一个简单的例子,有两个线程thread1负责写, thread2负责读,当它们操作同一个对象时,会发现由于thread1 与 thread2是同时执行的,因

25、此可能thread1修改了数据而thread2 读出的仍为旧数据,此时用户将无法获得预期的结果。问题之所以产生主要是由于资源使用协调不当( 不同步 ) 造成的。以前,这个问题一般由操作系统解决,而 Java 提供了自己协调资源的方法。Java 提供了同步方法和同步状态来协调资源。Java 规定:被宣布为同步( 使用 Synchronized关键字 ) 的方法,对象或类数据,在任何一个时刻只能被一个线程使用。通过这种方式使资源合理使用,达到线程同步的目的。我们将程序5.1 的类 MyThread 中的方法run()改成如下所示( 见程序片段5.3),并加入一个类SynchronizedShow实

26、现同步,大家可以运行看到执行结果:每次执行Show() 的只有一个线程。例5.3 ThreadTest3.java片段public void run()int i=0;while(keepRunning) i+;/i代表循环次数/ 输出结果SynchronizedShow.show(getName(),i);SynchronizedShow.println(getName()+is dead!);class SychronizedShow/ 方法 show(String,int)被宣布为同步的方法,因此每次只有一个线程能调用这个方法public static synchronized void

27、 show(String,name,int i)int k;k=i;for(intj=0;jjdb在执行之前,请用带-g参数的javac对程序进行编译,本节我们使用了前一章中check.java,第一步先重新编译方法如下:C:synetjavajavaexmplesjavac -g check.java用下面的方法可以进入jdb,可以直接在jdb后紧接要调试的类名,也可缺省,在进入jdb后利用load载入要调试的类。C:MyDemodawnjdb CheckInitializing jdb.0xe8d370:class(Check)在 Check 这一类名前的16 进制数是Check 类在 J

28、ava 运行时的标识。进入了 jdb后,可以使用 help来获取所需的使用信息: help* command list *run class args- start execution of applications main classthreads threadgroup- list threadsthread- set default threadsuspend thread id(s)- suspend threads (default: all)resume thread id(s)- resume threads (default: all)where thread id | al

29、l- dump a threads stackwherei thread id | all- dump a threads stack, with pc infoup n frames- move up a threads stackdown n frames- move down a threads stackkill- kill a thread with the given exception objectinterrupt- interrupt a threadprint- print value of expressiondump- print all object informat

30、ioneval- evaluate expression_r(same as print)set =- assign new value to field/variable/array elementlocals- print all local variables in current stack frameclasses- list currently known classesclass- show details of named classmethods- list a classs methodsfields- list a classs fieldsthreadgroups- l

31、ist threadgroupsthreadgroup- set current threadgroupstop in .(argument_type,.)- set a breakpoint in a methodstop at : - set a breakpoint at a line clear .(argument_type,.)- clear a breakpoint in a methodclear : - clear a breakpoint at a lineclear- list breakpointscatch- break when specified exceptio

32、n thrownignore- cancel catch for the specified exceptionwatch access|all .- watch access/modifications to a fieldunwatch access|all .- discontinue watching access/modifications to a fieldtrace methods thread - trace method entry and exituntrace methods thread - stop tracing method entry and exitstep

33、- execute current linestep up- execute until the current method returns to its callerstepi- execute current instructionnext- step one line (step OVER calls)cont- continue execution from breakpointlist line number|method - print source codeuse (or sourcepath) source file path- display or change the s

34、ource pathexclude class id . | none- do not report step or method events for specified classes classpath - print classpath info from target VMmonitor- execute command each time the program stopsmonitor- list monitorsunmonitor- delete a monitorread- read and execute a command filelock- print lock inf

35、o for an objectthreadlocks thread id - print lock info for a threaddisablegc- prevent garbage collection of an objectenablegc- permit garbage collection of an object!- repeat last command- repeat command n timeshelp (or ?)- list commandsversion- print version informationexit (or quit)- exit debugger

36、: 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 .jdbrcin user.home or user.dir利用命令stop in .可以在方法中设置断点,用命令run 运行方法。stop in Check.mainBreakpoint set Check.mainrun Checkrunning.main1Breakpoint hit: Check.main(Chech:18)mai

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论