Java语言程序设计(第三版-清华)第8章new_第1页
Java语言程序设计(第三版-清华)第8章new_第2页
Java语言程序设计(第三版-清华)第8章new_第3页
Java语言程序设计(第三版-清华)第8章new_第4页
Java语言程序设计(第三版-清华)第8章new_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

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

文档简介

第九章线程1目录Java中的线程线程的生命周期Thread的子类创立线程使用Runable接口线程的常用方法线程的优先级线程同步在同步方法中使用wait()、notify和notifyAll()方法挂起、恢复和终止线程本章小结2线程的概念进程和线程的区别〔Example9_11)进程一个独立程序的每一次运行称为一个进程,例如用字处理软件编辑文稿时,同时翻开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程设置一个进程要占用相当一局部处理器时间和内存资源大多数操作系统不允许进程访问其他进程的内存空间,进程间的通信很不方便,编程模型比较复杂进程通信方式共享存储器系统、消息传到机制、管道通信3线程一个程序中多段代码同时并发执行,称为多线程通过多线程,一个进程外表上看同时可以执行一个以上的任务——并发创立线程比创立进程开销要小得多,线程之间的协作和数据交换也比较容易(进程独站资源)线程间共享资源〔内存、代码、数据〕有利于并行处理线程的概念(续)4线程的状态与生命周期新建:当一个Thread类或其子类的对象被声明并创立时,新生的线程对象处于新建状态。此时它已经有了相应的内存空间和其他资源。就绪状态:线程等待CPU运行状态:start()方法开始执行中断(阻塞)状态:sleep(),wait(),I/O完成or发布I/O请求sleep():使当前线程进入等待状态,参数设定其等待时间wait():使当前线程进入等待状态,调用nofify(),ornotifyAll(),使其重新进入线程等待队列死亡:run()方法完成stop()方法被调用5LifeCycleofThread6诞生状态线程刚刚被创立就绪状态线程的start方法已被执行线程已准备好运行运行状态处理机分配给了线程,线程正在运行阻塞状态〔Blocked〕在线程发出输入/输出请求且必须等待其返回遇到用synchronized标记的方法而未获得其监视器暂时不能进入执行时休眠状态〔Sleeping〕执行sleep方法而进入休眠死亡状态线程已完成或退出线程的几种根本状态(续)7主线程:Java应用程序总是从主类的main方法开始执行。当JVM加载代码,发现main方法之后,启动的线程称作“主线程”,该线程负责执行main方法。在main方法的执行中再创立的线程,就称为程序中的其它线程。如果main方法中没有创立其他的线程,那么当main方法执行完最后一个语句,JVM就会结束Java应用程序。如果main方法中又创立了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,main方法即使执行完最后的语句,JVM也不会结束程序,JVM一直要等到程序中的所有线程都结束之后,才结束Java应用程序。8Java中创立线程的两种方法Thread类的子类创立线程对象,子类重写Thread类中的run()方法使用Thread类直接创立线程对象,但需要使用Runable接口9Thread类Thread类在Java程序中创立多线程的方法之一是继承Thread类封装了Java程序中一个线程对象需要拥有的属性和方法从Thread类派生一个子类,并创立这个子类的对象,就可以产生一个新的线程。这个子类应该重写Thread类的run〔〕方法,在run方法中写入需要在新线程中执行的语句段。这个子类的对象需要调用start方法来启动,新线程将自动进入run方法。原线程将同时继续往下执行它位于java.lang包中,因而程序开头不用import任何包就可直接使用例子:Example9_1.java10publicclassExample9_1{publicstaticvoidmain(Stringargs[]){Lefthandleft;Righthandright;left=newLefthand();//创立线程right=newRighthand();left.start();right.start();for(inti=1;i<=3;i++){("我是主线程");}}}classLefthandextendsThread{publicvoidrun(){for(inti=1;i<=3;i++){("我是左手线程");}}}classRighthandextendsThread{publicvoidrun(){for(inti=1;i<=3;i++){("我是右手线程");}}}我是主线程我是主线程我是主线程我是左手线程我是左手线程我是左手线程我是右手线程我是右手线程我是右手线程11Thread类(续)

在新线程中完成计算某个整数的阶乘publicclassEx8_1{publicstaticvoidmain(String[]args){ System.out.println("mainthreadstarts"); FactorialThreadthread=newFactorialThread(10);

thread.start();

System.out.println("mainthreadends");}}classFactorialThreadextends

Thread{privateintnum;publicFactorialThread(intnum){this.num=num;

}

12publicvoidrun(){inti=num;intresult=1;System.out.println("newthreadstarted");while(i>0){ result=result*i; i=i-1;}System.out.println("Thefactorialof"+num+"is"+result);System.out.println("newthreadends");}}运行结果mainthreadstartsmainthreadendsnewthreadstartedThefactorialof10is3628800newthreadendsThread类(续)

13结果说明main线程已经执行完后,新线程才执行完main函数调用thread.start()方法启动新线程后并不等待其run方法返回就继续运行(执行()),thread.run函数在一边单独运行,不影响原来的main函数的运行源程序修改如果启动新线程后希望主线程多持续一会再结束,可在start语句后加上让当前线程〔main〕休息1毫秒的语句:try{Thread.sleep(1);}catch(Exceptione){};Thread类(续)

14修改后运行结果mainthreadstartsnewthreadstaredThefactorialof10is3628800newthreadendsmainthreadends运行结果说明新线程结束后main线程才结束例子Ex8_1.javaThread类(续)

——例8_1修改后运行结果15Thread类(续)

——常用API函数名称说明publicThread()构造一个新的线程对象,默认名为Thread-n,n是从0开始递增的整数publicThread(Runnabletarget)构造一个新的线程对象,以一个实现Runnable接口的类的对象为参数。默认线程名为Thread-n,n是从0开始递增的整数publicThread(Stringname)构造一个新的线程对象,并同时指定线程名publicstaticThreadcurrentThread()返回当前正在运行的线程对象publicstaticvoidyield()使当前线程对象暂停,允许别的线程开始运行publicstaticvoidsleep(longmillis)使当前线程暂停运行指定毫秒数,但此线程并不失去已获得的锁旗标。16publicvoidstart()启动线程,JVM将调用此线程的run方法,结果是将同时运行两个线程,当前线程和执行run方法的线程publicvoidrun()Thread的子类应该重写此方法,内容应为该线程应执行的任务。publicfinalvoidstop()停止线程运行,释放该线程占用的对象锁旗标。publicvoidinterrupt()打断此线程publicfinalvoidjoin()在当前线程中加入调用join方法的线程A,直到线程A死亡才能继续执行当前线程publicfinalvoidjoin(longmillis)在当前线程中加入调用join方法的线程A,直到到达参数指定毫秒数或线程A死亡才能继续执行当前线程Thread类(续)

——常用API函数17publicfinalvoidsetPriority(intnewPriority)设置线程优先级publicfinalvoidsetDaemon(Booleanon)设置是否为后台线程,如果当前运行线程均为后台线程则JVM停止运行。这个方法必须在start()方法前使用publicfinalvoidcheckAccess()判断当前线程是否有权力修改调用此方法的线程publicvoidsetName(Stringname)更改本线程的名称为指定参数publicfinalbooleanisAlive()测试线程是否处于活动状态,如果线程被启动并且没有死亡则返回trueThread类(续)

——常用API函数18创立3个新线程,每个线程睡眠一段时间〔0~6秒〕,然后结束publicclassEx8_2{publicstaticvoidmain(String[]args){//创立并命名每个线程TestThreadthread1=newTestThread("thread1");TestThreadthread2=newTestThread("thread2");TestThreadthread3=newTestThread("thread3");("Startingthreads");thread1.start();//启动线程1thread2.start();//启动线程2thread3.start();//启动线程3("Threadsstarted,mainends\n");}}Thread类(续)

——例8_219classTestThreadextendsThread{privateintsleepTime;publicTestThread(Stringname){super(name);//调用父类构造函数为线程命名

sleepTime=(int)(Math.random()*6000);

}publicvoidrun(){try{(getName()+"goingtosleepfor"+sleepTime);

Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};(getName()+"finished"}}Thread类(续)

——例8_220运行结果StartingthreadsThreadsstarted,mainendsthread1goingtosleepfor3519thread2goingtosleepfor1689thread3goingtosleepfor5565thread2finishedthread1finishedthread3finished说明由于线程3休眠时间最长,所以最后结束,线程2休眠时间最短,所以最先结束每次运行,都会产生不同的随机休眠时间,所以结果都不相同Thread类(续)

——例8_2运行结果21Runnable接口Runnable接口在编写复杂程序时相关的类可能已经继承了某个基类,而Java不支持多继承,在这种情况下,便需要通过实现Runnable接口来生成多线使用Thread创立线程对象时,通常使用的构造方法是:Thread〔Runnabletarget〕该构造方法中的参数是一个Runnable类型的接口,因此,在创立线程

对象时必须向构造方法的参数传递一个实现Runnable接口类的实例,

该实例对象称作所创线程的目标对象.当线程调用start方法后,一旦轮到它来享用CPU资源,目标对象就会自动调用接口中的run方法〔接口回调〕.对于使用同一目标对象的线程,目标对象的成员变量自然就是这些线程的共享数据单元不同run()方法中的局部变量互不干扰。修改Ex8_1.java

例子:workspace/ThreadDemo2_2.java〔java2006/example9/ThreadDemo1_1,ThreadDemo2_2〕例子:Example9_3.javaTestThreadextendsThread{…..}TestThreadimplementsRunnable{newThread(Runnableth).start}22使用Runnable接口实现Ex8_1功能(使用一个目标对象)publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadt=newFactorialThread(10);newThread(t).start();//创立Thread对象System.out.println("newthreadstarted,mainthreadends");}}Runnable接口(续)

——例8_1_1Runnable接口类的实例23classFactorialThreadimplementsRunnable{privateintnum;publicFactorialThread(intnum){this.num=num;

}publicvoidrun(){inti=num;intresult=1;while(i>0){ result=result*i; i=i-1;}System.out.println("Thefactorialof"+num+"is"+result);System.out.println("newthreadends");}}Runnable接口(续)

——例8_324使用Runnable接口实现例8_2功能〔使用不同目标对象〕publicclassEx8_4{publicstaticvoidmain(String[]args){ TestThreadthread1=newTestThread();TestThreadthread2=newTestThread();TestThreadthread3=newTestThread();("Startingthreads");

newThread(thread1,"Thread1").start();newThread(thread2,"Thread2").start();newThread(thread3,"Thread3").start();

("Threadsstarted,mainends\n");}}Runnable接口(续)

——例8_4传递一个实现Runnable接口类的实例,并启动线程25classTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()

{sleepTime=(int)(Math.random()*6000);

}publicvoidrun(){try{(

Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);

Thread.sleep(sleepTime);

}catch(InterruptedExceptionexception){};

(Thread.currentThread().getName()+"finished");

}}Runnable接口(续)

——例8_4StartingthreadsThreadsstarted,mainendsThread2goingtosleepfor1498Thread1goingtosleepfor4544Thread3goingtosleepfor3251Thread2finishedThread3finishedThread1finished26线程间的数据共享代码共享多个线程的执行代码来自同一个类的run方法时,即称它们共享相同的代码数据共享当共享访问相同的对象时,即它们共享相同的数据不同线程的run()方法中的局部变量互不干扰〔Example9_5_1.java〕使用Runnable接口可以轻松实现多个线程共享相同数据,只要用同一个实现了Runnable接口的实例作为参数创立多个线程即可〔Ex8_5.java,p233-例9.3〕27classExample9_5_1{public

static

voidmain(Stringargs[]){

Movemove=newMove();

newThread(move,"zhangsan").start();

newThread(move,"lisi").start();}}28classMoveimplementsRunnable{

//inti=0;

public

voidrun(){inti=0;

while(i<=5){if(Thread.currentThread().getName().equals("zhangsan")){i=i+1;System.out.println(Thread.currentThread().getName()+"线程的局部变量i="+i);}

else

if(Thread.currentThread().getName().equals("lisi")){i=i+1;System.out.println(Thread.currentThread().getName()+"线程的局部变量i="+i);}

try{Thread.sleep(800);}

catch(InterruptedExceptione){}}}}29修改例8_4,只用一个Runnable类型的对象为参数创立3个新线程。publicclassEx8_5{publicstaticvoidmain(String[]args){ TestThreadthreadobj=newTestThread();("Startingthreads");

newThread(threadobj,"Thread1").start();newThread(threadobj,"Thread2").start();newThread(threadobj,"Thread3").start();

("Threadsstarted,mainends\n");}}线程间的数据共享(续)

——例8_530classTestThreadimplementsRunnable{ privateintsleepTime; publicTestThread()

{sleepTime=(int)(Math.random()*6000);

} publicvoidrun()

{try{(Thread.currentThread().getName()+"goingtosleepfor"+ sleepTime);Thread.sleep(sleepTime);

}catch(InterruptedExceptionexception){}; (Thread.currentThread().getName()+"finished"); }}线程间的数据共享(续)

——例8_531运行结果StartingthreadsThread1goingtosleepfor966Thread2goingtosleepfor966Threadsstarted,mainendsThread3goingtosleepfor966Thread1finishedThread2finishedThread3finished说明因为是用一个Runnable类型对象创立的3个新线程,这三个线程就共享了这个对象的私有成员sleepTime,在本次运行中,三个线程都休眠了966毫秒线程间的数据共享(续)

——例8_5运行结果32publicclassEx8_6{ publicstaticvoidmain(String[]args){ SellTicketst=newSellTickets();newThread(t).start();

newThread(t).start(); newThread(t).start(); }}线程间的数据共享(实际应用)

——例8_6用三个线程模拟三个售票口,总共出售200张票-用3个线程模仿3个售票口的售票行为-这3个线程应该共享200张票的数据33classSellTicketsimplementsRunnable{ privateinttickets=200;

publicvoidrun(){

while(tickets>0){ (Thread.currentThread().getName()+ "issellingticket"+tickets--); } }}线程间的数据共享(续)

——例8_634运行结果选最后几行如下Thread-2issellingticket6Thread-1issellingticket5Thread-0issellingticket4Thread-2issellingticket3Thread-1issellingticket2Thread-0issellingticket1说明在这个例子中,创立了3个线程,每个线程调用的是同一个SellTickets对象中的run()方法,访问的是同一个对象中的变量〔tickets〕如果是通过创立Thread类的子类来模拟售票过程,再创立3个新线程,那么每个线程都会有各自的方法和变量,虽然方法是相同的,但变量却是各有200张票,因而结果将会是各卖出200张票,和原意就不符了线程间的数据共享(续)

——例8_6运行结果35publicvoidstart()启动线程,JVM将调用此线程的run方法,结果是将同时运行两个线程,当前线程和执行run方法的线程publicvoidrun()Thread的子类应该重写此方法,内容应为该线程应执行的任务。publicfinalvoidstop()停止线程运行,释放该线程占用的对象锁旗标。publicvoidinterrupt()打断此线程publicfinalvoidjoin()在当前线程中加入调用join方法的线程A,直到线程A死亡才能继续执行当前线程publicfinalvoidjoin(longmillis)在当前线程中加入调用join方法的线程A,直到到达参数指定毫秒数或线程A死亡才能继续执行当前线程Thread类(续)

——常用API函数36interrupt()方法举例publicclassExample9_9{publicstaticvoidmain(Stringargs[]){Aa=newA();();();}}classAimplementsRunnable{Threadstudent,teacher;A(){teacher=newThread(this);student=newThread(this);teacher.setName("王教授");student.setName("张三");}37

publicvoidrun(){if(Thread.currentThread()==student){try{System.out.println(student.getName()+"正在睡觉,不听课");Thread.sleep(1000*60*60);}catch(InterruptedExceptione){System.out.println(student.getName()+"被老师叫醒了");}System.out.println(student.getName()+"开始听课");}38

elseif(Thread.currentThread()==teacher){for(inti=1;i<=3;i++){("上课!");try{Thread.sleep(500);}catch(InterruptedExceptione){}}

errupt();//吵醒student}}}interrupt()方法使student线程发生InterruptException,从而结束休眠39GUI线程Example9_1140多线程的同步控制有时线程之间彼此不独立、需要同步(相互配合)线程间的互斥同时运行的几个线程需要共享一个〔些〕数据一个线程对共享的数据进行操作时,不允许其他线程打断它,否那么会破坏数据的完整性。即被多个线程共享的数据,在某一时刻只允许一个线程对其进行操作“生产者/消费者”问题〔工资管理员/雇员〕生产者产生数据,消费者消费数据,具体来说,假设有一个Java应用程序,其中有一个线程负责往数据区写数据,另一个线程从同一数据区中读数据,两个线程可以并行执行〔类似于流水线上的两道工序〕如果数据区已满,,生产者要等消费者取走一些数据后才能再放;而当数据区没有数据时,消费者要等生产者放入一些数据后再取41线程同步的概念,包括互斥和协作互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据。因此有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区〔临界区〕协作:多个线程可以有条件地同时操作共享数据。执行监视区代码的线程在条件满足的情况下可以允许其它线程进入监视区〔临界区〕多线程的同步控制(续)

——线程同步(Synchronization)42

ProducerandConsumerHolderProducerInput-Dataq0q0…qnq1ProducerInput-Dataq1ConsumerOutputDataqn+1ProducerInput-Dataqn+143synchronized——线程同步关键字把需要修改数据的方法用关键字synchronized来修饰,用于指定需要同步的代码段或方法,也就是监视区当一个线程A使用一个synchronized修饰的方法时,其他线程想使用这个方法时就必须等待,直到线程A使用完该方法〔除非线程A使用wait主动让出CUP资源〕.当被synchronized限定的代码段执行完,就释放锁旗标〔信号量〕例子:Example9_13.java多线程的同步控制(续)

——synchronized关键字44线程间的通信为了更有效地协调不同线程的工作,需要在线程间建立沟通渠道,通过线程间的“对话”来解决线程间的同步问题类的一些方法为线程间的通讯提供了有效手段一个线程在使用的同步方法中时,可能根据问题的需要,必须使用wait()(挂起)方法使本线程等待,暂时让出CPU的使用权,并允许其它线程使用这个同步方法。其它线程如果在使用这个同步方法时如果不需要等待,那么它用完这个同步方法的同时,应当执行notify(),notifyAll()〔恢复〕方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。例子:Example9_14.java,Ex8_8.java,Ex8_9.java45线程的优先级每个Java线程都有一个优先级,其范围都在1和10之间。默认情况下,每个线程的优先级都设置为5在线程A运行过程中创立的新的线程对象B,初始状态具有和线程A相同的优先级如果A是个后台线程,那么B也是个后台线程可在线程创立之后的任何时候,通过setPriority(intpriority)方法改变其原来的优先级线程的优先级(续)46基于线程优先级的线程调度具有较高优先级的线程比优先级较低的线程优先执行对具有相同优先级的线程,Java的处理是随机的底层操作系统支持的优先级可能要少于10个,这样会造成一些混乱。因此,只能将优先级作为一种很粗略的工具使用。最后的控制可以通过明智地使用yield()函数来完成我们只能基于效率的考虑来使用线程优先级,而不能依靠线程优先级来保证算法的正确性线程的优先级(续)47假设某线程正在运行,那么只有出现以下情况之一,才会使其暂停运行一个具有更高优先级的线程变为就绪状态〔Ready〕;由于输入/输出〔或其他一些原因〕、调用sleep、wait、yield方法使其发生阻塞;对于支持时间分片的系统,时间片的时间期满线程的优先级(续)48创立两个具有不同优先级的线程,都从1递增到400000,每增加50000显示一次publicclassEx8_13{publicstaticvoidmain(String[]args){ TestThread[]runners=newTestThread[2];for(inti=0;i<2;i++)runners[i]=newTestThread(i);runners[0].setPriority(2);//设置第一个线程优先级为2runners[1].setPriority(3);//设置第二个线程优先级为3for(inti=0;i<2;i++)runners[i].start();}}线程的优先级(续)

——例8_1349classTestThreadextendsThread{ privateinttick=1; privateintnum; publicTestThread(inti){this.num=i; } publicvoidrun(){ while(tick<400000){tick++;if((tick%50000)==0){//每隔5000进行显示

("Thread#"+num+",tick="+tick);yield();//放弃执行权

}}} }线程的优先级(续)

——例8_1350线程的优先级(续)

——例8_13运行结果运行结果Thread#1,tick=50000Thread#1,tick=100000Thread#1,tick=150000Thread#1,tick=200000Thread#1,tick=250000Thread#1,tick=300000Thread#1,tick=350000Thread#1,tick=400000Thread#0,tick=50000Thread#0,tick=100000Thread#0,tick=150000Thread#0,tick=200000Thread#0,tick=250000Thread#0,tick=300000Thread#0,tick=350000Thread#0,tick=400000结果说明具有较高优先级的线程1一直运行到结束,具有较低优先级的线程0才开始运行虽然具有较高优先级的线程1调用了yield方法放弃CPU资源,允许线程0进行争夺,但马上又被线程1抢夺了回去,所以有没有yield方法都没什么区别51如果在yield方法后增加一行sleep语句,让线程1暂时放弃一下在CPU上的运行,哪怕是1毫秒,那么线程0也可以有时机被调度。修改后的run方法如下publicvoidrun(){ while(tick<400000){tick++;if((tick%50000)==0){("Thread#"+num+",tick="+tick);yield();try{sleep(1);}catch(Exceptione){};}}} 线程的优先级(续)

——例8_13修改52线程的优先级(续)

——例8_13修改后运行结果运行结果Thread#1,tick=50000Thread#1,tick=100000Thread#1,tick=150000Thread#1,tick=200000Thread#0,tick=50000Thread#1,tick=250000Thread#1,tick=300000Thread#0,tick=100000Thread#1,tick=350000Thread#1,tick=400000Thread#0,tick=150000Thread#0,tick=200000Thread#0,tick=250000Thread#0,tick=300000Thread#0,tick=350000Thread#0,tick=400000说明具有较低优先权的线程0在线程1没有执行完毕前也获得了一局部执行,但线程1还是优先完成了执行通常,我们在一个线程内部插入yield()语句,这个方法会使正在运行的线程暂时放弃执行,这是具有同样优先级的线程就有时机获得调度开始运行,但较低优先级的线程仍将被忽略不参加调度53本章小结本章内容线程的根底知识线程的生命周期线程的优先级本章要求了解线程的概念学会如何通过Thread类和Runnable接口创立线程,如何实现多线程的资源共享和通信,及如何控制线程的生命掌握线程同步的方法理解线程优先级的概念,以及基于优先级的线程调度54/holderholdingergersclassHoldInteger{ intshareInt=-1; booleanmoreData=true; publicvoidsetSharedInt(intval){shareInt=val;} publicintgetSharedInt(){returnshareInt;} publicvoidsetMoreData(booleanb){moreData=b;} publicbooleanhasMoreData(){returnmoreData;}}55//producerproducesintegersandputthemintoholderclassProducIntegerextendsThread{ HoldIntegerpHold; publicProducInteger(HoldIntegerh) { pHold=h; } publicvoidrun() { for(intcount=0;count<10;count++){

//sleepforrandominterval try{ Thread.sleep((int)(Math.random()*300)); } catch(InterruptedExceptione){ System.err.println(e.toString()); } pHold.setSharedInt(count); System.out.println("ProdecersetshareIntto"+count); }//setMoreDatatofalsewhencount<10.Itmeansholderisfull pHold.setMoreData(false); }}56//consumergetintegersfromholderclassConsumeIntegerextendsThread{ HoldIntegercHold; publicConsumeInteger(HoldIntegerh) { cHold=h; } publicvoidrun() { intval; while(cHold.hasMoreData()){ //sleepforrandominterval try{ Thread.sleep((int)(Math.random()*3000)); } catch(InterruptedExceptione){ System.err.println(e.toString());} val=cHold.getSharedInt();System.out.println("Consumerretrieved"+val);} }}57publicclasssynDemo{publicstaticvoidmain(Stringargs[]){HoldIntegerh=newHoldInteger();ProducIntegerp=newProducInteger(h);ConsumeIntegerc=newConsumeInteger(h);p.start();c.start();}}返回58运行结果ProdecersetshareIntto0ProdecersetshareIntto1ProdecersetshareIntto2ProdecersetshareIntto3ProdecersetshareIntto4Consumerretrieved4ProdecersetshareIntto5ProdecersetshareIntto6ProdecersetshareIntto7ProdecersetshareIntto8ProdecersetshareIntto9Consumerretrieved9返回59挂起有时候两个线程并不是同步的,即不涉及都需要调用一个同步方法,但线程也可能需要暂时的挂起。所谓挂起一个线程就是让线程暂时让出CPU的使用权限,暂时停止执行,但停止执行的持续时间不确定,因此不能使用sleep方法暂停线程。挂起一个线程需使用wait方法,即让准备挂起的线程调用wait方法,主动让出CPU的使用权限.恢复

为了恢复该线程,其它线程在占有CUP资源期间,让挂起的线程的目标对象执行notifyAll()方法,使得挂起的线程继续执行;如果线程没有目标对象,为了恢复该线程,其它线程在占有CUP资源期间,让挂起的线程调用notifyAll()方法,使挂起的线程继续执行。返回60Example9_13.java局部代码publicsynchronizedvoid存取(intnumber)//存取方法{if(Thread.curre

温馨提示

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

评论

0/150

提交评论