java面向对象第十章-Java线程_第1页
java面向对象第十章-Java线程_第2页
java面向对象第十章-Java线程_第3页
java面向对象第十章-Java线程_第4页
java面向对象第十章-Java线程_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

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

文档简介

第十章Java线程什么是进程、线程创立线程的两种方法线程的生命周期线程的类型分析1.什么是进程、线程进程:当前正在执行的程序,称为进程(progress) 例如:在进行网上购物时,可以边听音乐、收发Mail、QQ聊天等多个程序在运行。可通过windows任务管理器查看。 每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比方在Windows系统中,一个运行的exe就是一个进程。

说明:对于单CPU无法同时运行多个进程,只能交替轮流执行多个程序。在某一时刻,CPU执行的进程其实只有一个。1.1进程与线程在windows中可以通过任务管理器查看进程说明:CPU是一种非常珍贵的资源,它直接影响程序的运行情况。线程线程是进程中程序代码的一个执行序列,是一种比进程更小的执行单位,一个进程可以包含多个线程;线程也是一个动态的概念,包含产生、存在和消亡的过程;每个进程都有一段专用的内存区域,而线程间可以共享相同的内存单元(包括代码与数据),数据交换、实时通信、同步操作更方便。因此,线程得到广泛应用,例如:QQ等支持多线程是Java的重要特色,它提供了Thread类来实现多线程;Java中的线程可以认为是由三局部组成的:虚拟CPU:封装在类中,控制着整个线程的运行;执行的代码:传递给Thread类,由Thread类控制顺序执行;处理的数据:传递给Thread类,是在代码执行过程中所要处理的数据。1.2Java中的线程代码数据虚拟CPU以前的程序:一个入口,语句序列,一个出口。程序依次执行,这称为单线程。1.3多线程publicclassSequentialExample{//例1程序片段 publicstaticvoidmain(Stringargs[]){

newSequential("A").run(); newSequential("B").run(); }}classSequential{

Stringname=null; publicSequential(Stringn){//构造器 name=n; }

publicvoidrun(){ for(inti=0;i<3;i++){ try{

Thread.sleep(500);//休眠0.5秒

System.out.println("访问:"+name);

} }}程序运行结果访问:A访问:A访问:A访问:B访问:B访问:B多线程:CPU交替执行程序序列。//例2程序片段publicclassMultiThreadExample{ publicstaticvoidmain(Stringargs[]){ newMyThread("A").start(); newMyThread("B").start(); }}classMyThreadextendsThread{ publicMyThread(Stringn){//构造器 super(n); }

publicvoidrun(){ for(inti=0;i<3;i++){ try{

Thread.sleep(500);//休眠0.5秒

System.out.println("访问:"+getName());

}catch(InterruptedExceptione){} }}程序运行可能结果访问:A访问:B访问:A访问:B访问:A访问:B2.创立线程的两种方法从前面的例2可以知道:创立线程,最重要的是实现其中的run(),run()决定了线程所做的工作,又称为线程体。当线程开始时,代码publicvoidrun()被执行可用以下两种方法来创立线程类:继承线程类Thread实现Runnable接口Thread类和Runnable接口都在java.lang包中,是默认导入的,不必使用import语句。可通过继承Thread类,并重写其中的run()方法来定义线程体,以实现线程的具体行为,然后创立该子类的对象,并启动线程。其步骤为:(1)扩展类:2.1继承线程类Threadpublicclass线程类名extendsThread{ ……

publicvoidrun(){ ……//编写线程的代码 }}(2)创立线程类对象(3)启动线程:线程类对象.start();注意:不要在程序中直接调用线程的run()方法;启动线程并不意味着线程可以立即得到执行,这取决于线程资源的获取情况和CPU的占有情况。Thread类的构造方法:publicThread();publicThread(Runnabletarget);publicThread(Runnabletarget,Stringname);publicThread(Stringname);publicThread(ThreadGroupgroup,Stringname);…Threadt1=newThread(pp1);其中:target表示run()所在类,name是线程(组)名Thread类的常用方法:voidrun():线程所执行的代码voidstart():启动线程voidsleep(longmilis):让线程睡眠一段时间,此期间线程不消耗CPU资源voidinterrupt():中断线程booleanisAlive():判断线程是否处于活动状态(即已调用start)staticThreadcurrentThread():返回当前线程对象的引用voidsetName(StringthreadName):改变线程的名字StringgetName():获得线程的名字Thread类的常用方法(续):voidjoin([long

millis[,int

nanos]]):等待线程结束staticvoidyield():暂停当前线程,让其他线程执行voidsetDaemon(booleanon):设置为守护线程voidsetPriority(intp):设置线程的优先级notify()/notifyAll()/wait():从Object继承而来,用于线程间通信 以下几个方法出于平安问题考虑,现已不推荐使用:voiddestroy():销毁线程voidstop():终止线程的执行voidsuspend()/voidresume():挂起/恢复线程//例3用继承Thread类方法创立线程publicclassPingPong1extendsThread{ privateintdelay; privateStringmessage; publicPingPong1(Stringm,intr){ message=m; delay=r; } publicvoidrun(){ try{ for(;;){ System.out.println(message); sleep(delay);//休眠 } }catch(InterruptedExceptione){ return; } } publicstaticvoidmain(String[]args){ PingPong1t1=newPingPong1("ping",500); PingPong1t2=newPingPong1("pong",1000); t1.start(); t2.start(); }}程序运行结果(每次可能不同)pingpongpingpongpingpingpongpingPing…任何类都可以实现Runnable接口,而这个类的实例将用一个线程来调用,启动该类的run()方法。Runnable接口只有一个run()方法,其作用和Thread类的run()方法相同。创立步骤为:(1)定义目标类:2.2实现Runnable接口publicclasspingpong2

implementsRunnable{ ……

publicvoidrun(){ ……//编写线程的代码 }}(2)不能直接创立目标类对象并运行它,而是应该以目标类为参数创立Thread类的对象,例如:PingPong2pp1=newPingPong2(“ping”,500));Threadt1=newThread(pp1);(3)启动线程:以目标类为参数创立Thread类的对象.start(); 例如:t1.start();例4与例3的功能类似,只是使用了接口方法//例4利用接口Runnalbe方法创立线程publicclassPingPong2implementsRunnable{ privateintdelay; privateStringmessage; publicPingPong2(Stringm,intr){ message=m; delay=r; }//例4利用接口Runnalbe方法创立线程 publicvoidrun(){ try{ for(;;){ System.out.println(message); Thread.sleep(delay);//休眠 } }catch(InterruptedExceptione){ return; } } publicstaticvoidmain(String[]args){ PingPong2pp1=newPingPong2("ping",500); PingPong2pp2=newPingPong2("pong",1000); Threadt1=newThread(pp1); Threadt2=newThread(pp2); t1.start(); t2.start(); }}程序运行结果(每次可能不同)pingpongpingpongpingpingpongpingpingpongping…练习线程的创立分别用两种方法创立线程:〔1〕继承Thread类,要求线程体输出“由继承Thread类创立线程。”〔2〕实现Runnable接口,要求线程体输出“由实现Runnable接口创立线程。”由继承Thread类创立线程的方法简单方便,可以直接操作线程,无需使用Thread.currentThread()。但不能再继承其他类;使用Runnable接口方法可以将CPU,代码和数据分开,形成清晰的模型;还可以从其他类继承;保持程序风格的一致性。2.3两种方法的比较3.线程栈模型与线程的变量要理解线程调度的原理,以及线程执行过程,必须理解线程栈模型。线程栈是指某时刻时内存中线程调度的栈信息,当前调用的方法总是位于栈顶。

3.线程栈模型与线程的变量当程序执行到t.start()时,程序多出一个分支〔增加了一个调用栈B〕,这样,栈A、栈B并行执行。例5Join的应用classMyRunnableimplementsRunnable{ Stringname; MyRunnable(Stringstr){ name=str; } publicvoidrun(){//Runnable接口中方法 for(inti=0;i<=10;i++) System.out.println(name+""+i); } publicstaticvoidmain(String[]args)throwsInterruptedException{ MyRunnablemyr=newMyRunnable("myThread"); Threadt=newThread(myr);//创立线程 t.start();//启动 t.join(); System.out.println("run()方法执行完后线程状态:"+t.isAlive()); }}举例:创立线程,求两个数之间所有整数之和classSumThreadextendsThread{ intvar1,var2; longsum; SumThread(inti1,inti2){ var1=i1; var2=i2; } longgetSum(){ returnsum; } publicvoidrun(){//run()方法

for(inti=var1;i<=var2;i++) sum+=i; }}publicclassThread3{ publicstaticvoidmain(String[]args)throwsException{ SumThreadst=newSumThread(1,1000); st.start(); System.out.println(st.getSum());

}}结果:0classSumThreadextendsThread{ intvar1,var2; longsum; SumThread(inti1,inti2){ var1=i1; var2=i2; } longgetSum(){ returnsum; } publicvoidrun(){//run()方法

for(inti=var1;i<=var2;i++) sum+=i; }}publicclassThread3{ publicstaticvoidmain(String[]args)throwsException{ SumThreadst=newSumThread(1,1000); st.start(); st.join();//主线程main等待st线程结束

System.out.println(st.getSum()); }}结果:500500改进版本4.线程的生命周期新建死亡新建状态:当一个线程类实例被创立时,线程处于新建状态,此时的线程已经被初始化,并分配了资源 例如:ThreadmyThread=newMyThreadClass();就绪状态:已具备运行条件,进入线程队列,排队等待CPU。一旦获得CPU使用权,就可进入运行状态 例如:myThread.start();运行状态:当处于就绪状态的线程被调度获得CPU资源时,就进入了运行状态。定义在线程体中的run()方法被调用,从方法体的第一条语句开始顺序执行;阻塞状态:处于运行状态的线程因事件的发生,而导致让出CPU使用权,并终止当前执行,进行阻塞状态。线程的生命周期有五种状态: 线程由运行状态进入阻塞状态包含以下几种情况:调用了该线程的sleep()方法。等待其休眠指定时间之后,自动脱离阻塞状态;等待I/O操作完成。一旦I/O操作完成,系统自己调用特定的指令使该线程恢复可运行状态;调用wait()方法。调用notify()或notifyAll()方法可回到运行状态;调用suspend()方法。调用resume()方法可恢复线程的执行;死亡状态:线程通过以下两种途径进入死亡状态:自然终止:正常运行run()方法后终止;异常终止:调用stop()方法让一个线程终止运行。sleep():使一个线程在特定时间休眠,具体格式:publicstaticvoidsleep(longmillisec);(单位:毫秒)publicstaticvoidsleep(longmillisec,intnanosec);

(后一参数的单位:纳秒)yield():将CPU让予其它线程。这将导致正在运行的线程暂时停止,允许其他线程运行;正在休眠或等待的线程可通过调用interrupt()方法中断,这会导致抛出一个interruptedException异常;通过isInterrupted()方法,可以了解一个线程是否被中断;join():调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。5.线程的根本控制例6代码://线程唤醒的例子publicclassThreadInterruptDemoextendsThread{ publicvoidrun(){ System.out.println("休息,勿扰!"); try{ sleep(3600000); }catch(InterruptedExceptione){ System.out.println("啊,谁叫醒我的?"); } } publicstaticvoidmain(Stringargs[]){

ThreadInterruptDemot=newThreadInterruptDemo(); t.start(); errupt();//唤醒线程 }}程序运行结果休息,勿扰!啊,谁叫醒我的?例7代码://线程的join()方法publicclassThreadJoinDemoextendsThread{ publicstaticvoidmain(Stringargs[]){

MyRunnermyr=newMyRunner(); Threadt=newThread(myr); t.start(); try{

t.join(); }catch(InterruptedExceptione){ } for(inti=0;i<5;i++){ System.out.println("主线程:"+i); } }}classMyRunnerimplementsRunnable{

publicvoidrun(){ for(inti=0;i<5;i++) System.out.println("子线程:"+i); }}程序运行结果子线程:0子线程:1子线程:2子线程:3子线程:4主线程:0主线程:1主线程:2主线程:3主线程:4//例8线程状态转换publicclassThreadStatusDemo{ publicstaticvoidmain(Stringargs[]){ MyRunnerr=newMyRunner(); Threadt=newThread(r);//新建状态 t.start();//启动状态 }}classMyRunnerimplementsRunnable{

publicvoidrun(){//运行状态 for(inti=0;i<20;i++){ if(i%5==0&&i!=0){ try{ Thread.sleep(3000);//阻塞状态 }catch(InterruptedExceptione){ } } System.out.println("No."+i);//运行状态 } }}程序运行结果(当为5的倍数时休眠3秒钟)No.0No.1No.2No.3No.4No.5No.6……No.18No.19线程可以划分为两种类型:用户线程(第1种)由用户〔程序员〕创立在前台执行当用户线程运行时,JVM不会退出但在所有用户线程都执行完毕时,JVM将终止所有守护线程(包括垃圾收集器),然后退出主线程是用main()方法创立的6.线程的类型守护线程(第2种):是为其它线程提供效劳的线程,它一般应该是一个独立的线程,它的run()方法是一个无限循环;它们通常在后台执行,例如:定时器、垃圾回收器都是守护线程;某些用户创立的线程会通过调用setDaemon()方法在后台运行。使用守护线程的本卷须知:(1)thread.setDaemon(true)必须在thread.start()之前设置,否那么会跑出一个IllegalThreadStateException异常。不能把正在运行的常规线程设置为守护线程。

(2)在Daemon线程中产生的新线程也是Daemon的。

(3)局部任务不适合分配给Daemon来进行效劳,比方IIO读写。

例9代码://守护线程的例子publicclassDaemonThreadextendsThread{

publicvoidrun(){ while(true){ System.out.println("守护线程正在运行..."); } } publicstaticvoidmain(Stringargs[]){

DaemonThreaddt=newDaemonThread(); dt.setDaemon(true);//设置为后台线程 dt.start(); }}程序运行结果守护线程正在运行...守护线程正在运行...守护线程正在运行...守护线程正在运行...守护线程正在运行...…...问题:该线程最终能否自动终止?例10代码://文件输出的守护线程任务importjava.io.*;classTestRunnableimplementsRunnable{publicvoidrun(){try{Thread.sleep(1000);//守护线程阻塞1秒后运行

Filef=newFile(“F://daemon.txt");FileOutputStreamos=newFileOutputStream(f,true);os.write("daemon".getBytes());}catch(IOExceptione1){e1.printStackTrace();}catch(InterruptedExceptione2){e2.printStackTrace();}}}例10代码〔续〕:publicclassTestDemo2{publicstaticvoidmain(String[]args)throwsInterruptedException{Runnabletr=newTestRunnable();Threadthread=newThread(tr);

温馨提示

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

评论

0/150

提交评论