Java语言程序设计第8章课件_第1页
Java语言程序设计第8章课件_第2页
Java语言程序设计第8章课件_第3页
Java语言程序设计第8章课件_第4页
Java语言程序设计第8章课件_第5页
已阅读5页,还剩85页未读 继续免费阅读

下载本文档

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

文档简介

第8章线程郑莉JAVA语言程序设计1第8章线程郑莉JAVA语言程序设计1本讲内容线程基础线程的概念Thread类Runnable接口资源共享和线程同步线程间的通信线程的生命周期线程的优先级程序举例2本讲内容线程基础2线程的概念进程:程序的一次执行线程:一个进程中的多个控制流通过多线程,一个进程表面上看同时可以执行一个以上的任务——并发多数程序设计语言不支持并发,支持多线程要借助于操作系统“原语(primitives)”Java是第一个支持内置线程操作的主流编程语言线程基础3线程的概念进程:程序的一次执行线程基础3Thread类简介线程类需要继承Thread类Thread的构造函数

publicThread(StringthreadName)

publicThread()在线程的run方法中编写线程的主要任务sleep方法使线程休眠interrupt方法中断一个运行中的线程isAlive方法检查线程的状态setName方法设置线程名join方法等待线程结束,以执行当前线程线程基础4Thread类简介线程类需要继承Thread类线程基础例8_1在新线程中计算整数的阶乘publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadthread=newFactorialThread(10);thread.start();System.out.println("newthreadstarted,mainthreadends");}//endmain}线程基础5例8_1在新线程中计算整数的阶乘publicclass//classFactorialThreadcontrolsthreadexecutionclassFactorialThreadextendsThread{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");}}6//classFactorialThreadcontr运行结果如下:mainthreadstartsnewthreadstarted,mainthreadendsThefactorialof10is3628800newthreadends7运行结果如下:7例8_2创建3个新线程,每个线程睡眠任意0-6秒钟,然后结束。publicclassEx8_2{publicstaticvoidmain(String[]args){//创建并命名每个线程

TestThreadthread1=newTestThread("thread1");TestThreadthread2=newTestThread("thread2");TestThreadthread3=newTestThread("thread3");System.out.println("Startingthreads");thread1.start();//启动线程1thread2.start();//启动线程2thread3.start();//启动线程3System.out.println("Threadsstarted,mainends\n");}}线程基础8例8_2创建3个新线程,每个线程睡眠任意0-6秒钟,然后结classTestThreadextendsThread{privateintsleepTime;publicTestThread(Stringname)//构造函数

{super(name);//调用基类构造函数为线程命名

//获得随机休息毫秒数

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

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(getName()+"finished");

}}9classTestThreadextendsThrea运行结果为:StartingthreadsThreadsstarted,mainendsthread1goingtosleepfor3519thread2goingtosleepfor1689thread3goingtosleepfor5565thread2finishedthread1finishedthread3finished10运行结果为:10Runnable接口如果希望一个已经有基类的类支持多线程,则不能再继承Thread类了(Java不支持多继承)解决方法:使类实现Runnable接口,再与Thread类结合使用一个内部类提供Runnable的实现代码,将内部类的对象与Thread结合相对于Thread类,它更适合于多个线程处理同一资源线程基础11Runnable接口如果希望一个已经有基类的类支持多线程,则例8_3使用Runnable接口实现例8_1功能publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadt=newFactorialThread(10);newThread(t).start();System.out.println("newthreadstarted,mainthreadends");}//endmain}线程基础12例8_3使用Runnable接口实现例8_1功能publi//classFactorialThreadcontrolsthreadexecutionclassFactorialThreadimplementsRunnable{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");}}13//classFactorialThreadcontr例8_4使用Runnable接口实现例8_2功能publicclassEx8_4{publicstaticvoidmain(String[]args){//创建3个实现Runnable接口类的对象

TestThreadthread1=newTestThread();TestThreadthread2=newTestThread();TestThreadthread3=newTestThread();System.out.println("Startingthreads");//分别以三个对象为参数创建三个新线程,

//第二个参数为新线程命名并启动之

newThread(thread1,"Thread1").start();newThread(thread2,"Thread2").start();newThread(thread3,"Thread3").start();System.out.println("Threadsstarted,mainends\n");}}线程基础14例8_4使用Runnable接口实现例8_2功能publiclassTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()//构造方法

{//获得随机休息毫秒数sleepTime=(int)(Math.random()*6000);

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(Thread.currentThread().getName()+"finished");

}}15classTestThreadimplementsRu运行结果如下:StartingthreadsThread1goingtosleepfor1487Thread2goingtosleepfor1133Threadsstarted,mainendsThread3goingtosleepfor2328Thread2finishedThread1finishedThread3finished16运行结果如下:16资源共享和线程同步独立的同时运行的线程有时需要共享一些数据并且考虑到彼此的状态和动作。例如生产/消费问题:生产线程产生数据流,然后这些数据流再被消费线程消费。具体来说,假设一个Java应用程序,其中有一个线程负责往文件写数据,另一个线程从同一个文件中往出都数据,因为涉及到同一个资源,这里是同一个文件,这两个线程必须保证某种方式的同步。当多个线程的执行代码来自同一个类的实例(若干个)时,即称它们共享相同的代码,当共享访问相同的对象时,即它们共享相同的数据。使用Runnable接口可以轻松实现多个线程共享相同数据,只要用同一个实现了Runnable接口的实例作为参数创建多个线程就可以了。线程基础17资源共享和线程同步独立的同时运行的线程有时需要共享一些数据并例8_5修改例8_4//只用一个Runnable类型的对象为参数创建3个新线程。publicclassEx8_5{publicstaticvoidmain(String[]args){//只创建1个实现Runnable接口类的对象

TestThreadthread=newTestThread();System.out.println("Startingthreads");//只用一个Runnable类型对象为参数创建三个新线程,

//命名并启动之

newThread(thread,"Thread1").start();newThread(thread,"Thread2").start();newThread(thread,"Thread3").start();System.out.println("Threadsstarted,mainends\n");}}线程基础18例8_5修改例8_4//只用一个Runnable类型的对象classTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()//构造函数

{//获得随机休息毫秒数sleepTime=(int)(Math.random()*6000);

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(Thread.currentThread().getName()+"finished");

}}19classTestThreadimplementsRuStartingthreadsThread1goingtosleepfor966Thread2goingtosleepfor966Threadsstarted,mainendsThread3goingtosleepfor966Thread1finishedThread2finishedThread3finished20Startingthreads20例8_6用三个线程模拟三个售票口,总共出售200张票。publicclassEx8_6{ publicstaticvoidmain(String[]args) {//新建一个售票类的对象 SellTicketst=newSellTickets();//用此对象作为参数创建3个新线程并启动

newThread(t).start();

newThread(t).start(); newThread(t).start(); }}线程基础21例8_6用三个线程模拟三个售票口,总共出售200张票。puclassSellTicketsimplementsRunnable{ //将共享的资源作为私有变量privateinttickets=200;

publicvoidrun() { while(tickets>0)//直到没有票可售为止

{ System.out.println(Thread.currentThread().getName()+ "issellingticket"+tickets--); } }}22classSellTicketsimplementsR例8_7用两个线程模拟存票、卖票过程publicclassEx8_7{ publicstaticvoidmain(String[]args) {//新建一个票类对象,总票数作为参数 Ticketst=newTickets(10);

//以票类对象为参数创建存票线程对象,并启动newProducer(t).start();

//以同一个票类对象为参数创建售票线程,并启动newConsumer(t).start();

}}线程基础23例8_7用两个线程模拟存票、卖票过程publicclasclassTickets//票类{ intnumber=0;//票号

intsize;//总票数//表示目前是否有票可售

booleanavailable=false;//构造方法,传入总票数参数 publicTickets(intsize)

{ this.size=size; } }24classTickets//票类24classProducerextendsThread//存票线程{ Ticketst=null; publicProducer(Ticketst)//构造函数以一个票类对象为参数

{this.t=t;} publicvoidrun() {//限制循环条件为存票序号小于总票数 while((t.number)<t.size){ System.out.println("Producerputsticket"+(++t.number)); t.available=true;//可以卖票

} }}25classProducerextendsThreadclassConsumerextendsThread//售票线程{ Ticketst=null; inti=0; publicConsumer(Ticketst)//构造函数以一个票类对象为参数

{this.t=t; } publicvoidrun() {while(i<t.size)//循环条件为售票序号小于总票数

{ if(t.available==true&&i<=t.number)//有票且小于目前票序号

System.out.println("Consumerbuysticket"+(++i)); if(i==t.number)//如果票已售到当前序号,则不可售

t.available=false; } }}26classConsumerextendsThread运行结果Producerputsticket1Producerputsticket2Producerputsticket3Producerputsticket4Producerputsticket5Producerputsticket6Producerputsticket7Producerputsticket8Consumerbuysticket1Consumerbuysticket2Consumerbuysticket3Consumerbuysticket4Consumerbuysticket5Consumerbuysticket6Consumerbuysticket7Consumerbuysticket8Producerputsticket9Producerputsticket10死机(进入死循环)27运行结果27错误原因假如售票线程运行到t.available=false之前,CPU切换到执行存票线程,存票线程将available置为true,但再次切换到售票线程后,售票线程执行t.available=false,则由于售票号目前还是8,小于总票数,且存票线程已经结束不再能将t.available置为true,则售票线程陷入了死循环。线程基础28错误原因假如售票线程运行到t.available=false线程同步(Synchronization)Java使用的同步机制是监视器,支持线程的互斥与同步互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据。因此有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区。协作:多个线程可以有条件地同时操作共享数据执行监视区代码的线程在条件满足的情况下可以允许其它线程进入监视区。线程基础29线程同步(Synchronization)Java使用的同线程间的通信线程同步关键字——synchronized用于指定需要同步的代码段或方法,也就是监视区。wait(

)当前状态不适合本线程执行时,进入等待状态notify()随机唤醒一个等待的线程,本线程继续执行。notifyAll()唤醒所有等待的线程,本线程继续执行。线程基础30线程间的通信线程同步关键字——synchronized线程线程间的通信线程被唤醒以后,还要等发出唤醒消息者释放监视器,这期间关键数据仍可能被改变。被唤醒线程的线程可能有多个。(使用notifyAll时)。被唤醒的线程开始执行时,一定要判断当前状态是否适合自己运行。线程基础31线程间的通信线程被唤醒以后,还要等发出唤醒消息者释放监视器,例8_8实现例8_7功能。将同步方法放在共享的资源类Tickets中。publicclassEx8_8{ publicstaticvoidmain(String[]args) { Ticketst=newTickets(10); newProducer(t).start(); newConsumer(t).start(); }}线程基础32例8_8实现例8_7功能。将同步方法放在共享的资源类TicclassTickets{intsize;//票总数intnumber=0;//存票序号inti=0;//售票序号booleanavailable=false;//是否有待售的票publicTickets(intsize){this.size=size;}publicsynchronizedvoidput()//同步代码块,实现存票的功能{System.out.println("Producerputsticket"+(++number));available=true; } publicsynchronizedvoidsell()//同步代码块,实现售票的功能{if(available==true&&i<=number) System.out.println("Consumerbuysticket"+(++i));if(i==number)available=false; } }33classTickets33classConsumerextendsThread{Ticketst=null;//构造方法,使两线程共享票类对象publicConsumer(Ticketst){this.t=t;}publicvoidrun()//如果售票数小于限定总量,则不断售票{while(t.i<t.size)

t.sell();}}34classConsumerextendsThread3例8_9每存入一张票,就售一张票,售出后,再存入publicclassEx8_8{ publicstaticvoidmain(String[]args) { Ticketst=newTickets(10); newProducer(t).start(); newConsumer(t).start(); }}线程基础35例8_9每存入一张票,就售一张票,售出后,再存入publiclassTickets{ intsize; intnumber=0; inti=0; booleanavailable=false; publicTickets(intsize) {this.size=size;} publicsynchronizedvoidput() {if(available)//如果还有存票待售,则存票线程等待

try{wait();}catch(Exceptione){} System.out.println("Producerputsticket"+(++number)); available=true; notify(); ...//存票后唤醒售票线程开始售票

} 36classTickets36

publicsynchronizedvoidsell() {if(!available)//如果没有存票,则售票线程等待

try{wait();}catch(Exceptione){} if(i<=number)System.out.println("Consumerbuysticket"+(++i));if(i==number) {try{Thread.sleep(1);}catch(Exceptione){} available=false; } notify();//售票后唤醒存票线程开始存票

} }37 publicsynchronizedvoidsellclassProducerextendsThread{ Ticketst=null; publicProducer(Ticketst) { this.t=t; } publicvoidrun() { while(t.number<t.size) t.put(); } }38classProducerextendsThread3classConsumerextendsThread{ Ticketst=null; publicConsumer(Ticketst) { this.t=t; } publicvoidrun() { while(t.i<t.size) t.sell(); } }39classConsumerextendsThread3运行结果如下:Producerputsticket1Consumerbuysticket1Producerputsticket2Consumerbuysticket2Producerputsticket3Consumerbuysticket3Producerputsticket4Consumerbuysticket4Producerputsticket5Consumerbuysticket5Producerputsticket6Consumerbuysticket6Producerputsticket7Consumerbuysticket7Producerputsticket8Consumerbuysticket8Producerputsticket9Consumerbuysticket9Producerputsticket10Consumerbuysticket1040运行结果如下:40守护(Daemon)线程为了辅助其它线程而运行的线程不妨碍程序终止“垃圾回收”便是一个守护线程用setDaemon方法将线程设置为守护线程线程基础41守护(Daemon)线程为了辅助其它线程而运行的线程线程例8_10创建一个无限循环的守护线程publicclassEx8_10{ publicstaticvoidmain(String[]args) { ThreadTestt=newThreadTest(); t.setDaemon(true); t.start(); }}classThreadTestextendsThread{ publicvoidrun() { while(true){}}}42例8_10创建一个无限循环的守护线程publicclas线程的状态诞生状态线程刚刚被创建就绪状态线程的start方法已被执行线程已准备好运行运行状态处理机分配给了线程,线程正在运行阻塞状态(Blocked)在线程发出输入/输出请求且必须等待其返回,或遇到用synchronized标记的方法而未获得其监视器暂时不能进入执行时休眠状态(Sleeping)执行sleep方法而进入休眠死亡状态线程已完成或退出线程的生命周期43线程的状态诞生状态线程的生命周期434444线程优先级与调度Java线程优先级(priority)取值范围1-10时间片(Timeslicing)每个线程被赋予一定的处理机时间总是调度最高优先级的线程运行45线程优先级与调度Java线程优先级(priority)第8章线程郑莉JAVA语言程序设计46第8章线程郑莉JAVA语言程序设计1本讲内容线程基础线程的概念Thread类Runnable接口资源共享和线程同步线程间的通信线程的生命周期线程的优先级程序举例47本讲内容线程基础2线程的概念进程:程序的一次执行线程:一个进程中的多个控制流通过多线程,一个进程表面上看同时可以执行一个以上的任务——并发多数程序设计语言不支持并发,支持多线程要借助于操作系统“原语(primitives)”Java是第一个支持内置线程操作的主流编程语言线程基础48线程的概念进程:程序的一次执行线程基础3Thread类简介线程类需要继承Thread类Thread的构造函数

publicThread(StringthreadName)

publicThread()在线程的run方法中编写线程的主要任务sleep方法使线程休眠interrupt方法中断一个运行中的线程isAlive方法检查线程的状态setName方法设置线程名join方法等待线程结束,以执行当前线程线程基础49Thread类简介线程类需要继承Thread类线程基础例8_1在新线程中计算整数的阶乘publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadthread=newFactorialThread(10);thread.start();System.out.println("newthreadstarted,mainthreadends");}//endmain}线程基础50例8_1在新线程中计算整数的阶乘publicclass//classFactorialThreadcontrolsthreadexecutionclassFactorialThreadextendsThread{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");}}51//classFactorialThreadcontr运行结果如下:mainthreadstartsnewthreadstarted,mainthreadendsThefactorialof10is3628800newthreadends52运行结果如下:7例8_2创建3个新线程,每个线程睡眠任意0-6秒钟,然后结束。publicclassEx8_2{publicstaticvoidmain(String[]args){//创建并命名每个线程

TestThreadthread1=newTestThread("thread1");TestThreadthread2=newTestThread("thread2");TestThreadthread3=newTestThread("thread3");System.out.println("Startingthreads");thread1.start();//启动线程1thread2.start();//启动线程2thread3.start();//启动线程3System.out.println("Threadsstarted,mainends\n");}}线程基础53例8_2创建3个新线程,每个线程睡眠任意0-6秒钟,然后结classTestThreadextendsThread{privateintsleepTime;publicTestThread(Stringname)//构造函数

{super(name);//调用基类构造函数为线程命名

//获得随机休息毫秒数

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

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(getName()+"finished");

}}54classTestThreadextendsThrea运行结果为:StartingthreadsThreadsstarted,mainendsthread1goingtosleepfor3519thread2goingtosleepfor1689thread3goingtosleepfor5565thread2finishedthread1finishedthread3finished55运行结果为:10Runnable接口如果希望一个已经有基类的类支持多线程,则不能再继承Thread类了(Java不支持多继承)解决方法:使类实现Runnable接口,再与Thread类结合使用一个内部类提供Runnable的实现代码,将内部类的对象与Thread结合相对于Thread类,它更适合于多个线程处理同一资源线程基础56Runnable接口如果希望一个已经有基类的类支持多线程,则例8_3使用Runnable接口实现例8_1功能publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadt=newFactorialThread(10);newThread(t).start();System.out.println("newthreadstarted,mainthreadends");}//endmain}线程基础57例8_3使用Runnable接口实现例8_1功能publi//classFactorialThreadcontrolsthreadexecutionclassFactorialThreadimplementsRunnable{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");}}58//classFactorialThreadcontr例8_4使用Runnable接口实现例8_2功能publicclassEx8_4{publicstaticvoidmain(String[]args){//创建3个实现Runnable接口类的对象

TestThreadthread1=newTestThread();TestThreadthread2=newTestThread();TestThreadthread3=newTestThread();System.out.println("Startingthreads");//分别以三个对象为参数创建三个新线程,

//第二个参数为新线程命名并启动之

newThread(thread1,"Thread1").start();newThread(thread2,"Thread2").start();newThread(thread3,"Thread3").start();System.out.println("Threadsstarted,mainends\n");}}线程基础59例8_4使用Runnable接口实现例8_2功能publiclassTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()//构造方法

{//获得随机休息毫秒数sleepTime=(int)(Math.random()*6000);

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(Thread.currentThread().getName()+"finished");

}}60classTestThreadimplementsRu运行结果如下:StartingthreadsThread1goingtosleepfor1487Thread2goingtosleepfor1133Threadsstarted,mainendsThread3goingtosleepfor2328Thread2finishedThread1finishedThread3finished61运行结果如下:16资源共享和线程同步独立的同时运行的线程有时需要共享一些数据并且考虑到彼此的状态和动作。例如生产/消费问题:生产线程产生数据流,然后这些数据流再被消费线程消费。具体来说,假设一个Java应用程序,其中有一个线程负责往文件写数据,另一个线程从同一个文件中往出都数据,因为涉及到同一个资源,这里是同一个文件,这两个线程必须保证某种方式的同步。当多个线程的执行代码来自同一个类的实例(若干个)时,即称它们共享相同的代码,当共享访问相同的对象时,即它们共享相同的数据。使用Runnable接口可以轻松实现多个线程共享相同数据,只要用同一个实现了Runnable接口的实例作为参数创建多个线程就可以了。线程基础62资源共享和线程同步独立的同时运行的线程有时需要共享一些数据并例8_5修改例8_4//只用一个Runnable类型的对象为参数创建3个新线程。publicclassEx8_5{publicstaticvoidmain(String[]args){//只创建1个实现Runnable接口类的对象

TestThreadthread=newTestThread();System.out.println("Startingthreads");//只用一个Runnable类型对象为参数创建三个新线程,

//命名并启动之

newThread(thread,"Thread1").start();newThread(thread,"Thread2").start();newThread(thread,"Thread3").start();System.out.println("Threadsstarted,mainends\n");}}线程基础63例8_5修改例8_4//只用一个Runnable类型的对象classTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()//构造函数

{//获得随机休息毫秒数sleepTime=(int)(Math.random()*6000);

}publicvoidrun()//线程启动并开始运行后要执行的方法

{try{System.out.println(Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);Thread.sleep(sleepTime);//线程休眠

}catch(InterruptedExceptionexception){};//运行结束,给出提示信息System.out.println(Thread.currentThread().getName()+"finished");

}}64classTestThreadimplementsRuStartingthreadsThread1goingtosleepfor966Thread2goingtosleepfor966Threadsstarted,mainendsThread3goingtosleepfor966Thread1finishedThread2finishedThread3finished65Startingthreads20例8_6用三个线程模拟三个售票口,总共出售200张票。publicclassEx8_6{ publicstaticvoidmain(String[]args) {//新建一个售票类的对象 SellTicketst=newSellTickets();//用此对象作为参数创建3个新线程并启动

newThread(t).start();

newThread(t).start(); newThread(t).start(); }}线程基础66例8_6用三个线程模拟三个售票口,总共出售200张票。puclassSellTicketsimplementsRunnable{ //将共享的资源作为私有变量privateinttickets=200;

publicvoidrun() { while(tickets>0)//直到没有票可售为止

{ System.out.println(Thread.currentThread().getName()+ "issellingticket"+tickets--); } }}67classSellTicketsimplementsR例8_7用两个线程模拟存票、卖票过程publicclassEx8_7{ publicstaticvoidmain(String[]args) {//新建一个票类对象,总票数作为参数 Ticketst=newTickets(10);

//以票类对象为参数创建存票线程对象,并启动newProducer(t).start();

//以同一个票类对象为参数创建售票线程,并启动newConsumer(t).start();

}}线程基础68例8_7用两个线程模拟存票、卖票过程publicclasclassTickets//票类{ intnumber=0;//票号

intsize;//总票数//表示目前是否有票可售

booleanavailable=false;//构造方法,传入总票数参数 publicTickets(intsize)

{ this.size=size; } }69classTickets//票类24classProducerextendsThread//存票线程{ Ticketst=null; publicProducer(Ticketst)//构造函数以一个票类对象为参数

{this.t=t;} publicvoidrun() {//限制循环条件为存票序号小于总票数 while((t.number)<t.size){ System.out.println("Producerputsticket"+(++t.number)); t.available=true;//可以卖票

} }}70classProducerextendsThreadclassConsumerextendsThread//售票线程{ Ticketst=null; inti=0; publicConsumer(Ticketst)//构造函数以一个票类对象为参数

{this.t=t; } publicvoidrun() {while(i<t.size)//循环条件为售票序号小于总票数

{ if(t.available==true&&i<=t.number)//有票且小于目前票序号

System.out.println("Consumerbuysticket"+(++i)); if(i==t.number)//如果票已售到当前序号,则不可售

t.available=false; } }}71classConsumerextendsThread运行结果Producerputsticket1Producerputsticket2Producerputsticket3Producerputsticket4Producerputsticket5Producerputsticket6Producerputsticket7Producerputsticket8Consumerbuysticket1Consumerbuysticket2Consumerbuysticket3Consumerbuysticket4Consumerbuysticket5Consumerbuysticket6Consumerbuysticket7Consumerbuysticket8Producerputsticket9Producerputsticket10死机(进入死循环)72运行结果27错误原因假如售票线程运行到t.available=false之前,CPU切换到执行存票线程,存票线程将available置为true,但再次切换到售票线程后,售票线程执行t.available=false,则由于售票号目前还是8,小于总票数,且存票线程已经结束不再能将t.available置为true,则售票线程陷入了死循环。线程基础73错误原因假如售票线程运行到t.available=false线程同步(Synchronization)Java使用的同步机制是监视器,支持线程的互斥与同步互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据。因此有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区。协作:多个线程可以有条件地同时操作共享数据执行监视区代码的线程在条件满足的情况下可以允许其它线程进入监视区。线程基础74线程同步(Synchronization)Java使用的同线程间的通信线程同步关键字——synchronized用于指定需要同步的代码段或方法,也就是监视区。wait(

)当前状态不适合本线程执行时,进入等待状态notify()随机唤醒一个等待的线程,本线程继续执行。notifyAll()唤醒所有等待的线程,本线程继续执行。线程基础75线程间的通信线程同步关键字——synchronized线程线程间的通信线程被唤醒以后,还要等发出唤醒消息者释放监视器,这期间关键数据仍可能被改变。被唤醒线程的线程可能有多个。(使用notifyAll时)。被唤醒的线程开始执行时,一定要判断当前状态是否适合自己运行。线程基础76线程间的通信线程被唤醒以后,还要等发出唤醒消息者释放监视器,例8_8实现例8_7功能。将同步方法放在共享的资源类Tickets中。publicclassEx8_8{ publicstaticvoidmain(String[]args) { Ticketst=newTickets(10); newProducer(t).start(); newConsumer(t).start(); }}线程基础77例8_8实现例8_7功能。将同步方法放在共享的资源类TicclassTickets{intsize;//票总数intnumber=0;//存票序号inti=0;//售票序号booleanavailable=false;//是否有待售的票publicTickets(intsize){this.size=size;}publicsynchronizedvoidput()//同步代码块,实现存票的功能{System.out.println("Producerputsticket"+(++number));available=true; } publicsynchronizedvoidsell()//同步代码块,实现售票的功能{if(available==true&&i<=number) System.out.println("Consumerbuysticket"+(++i));if(i==number)available=false; } }78classTickets33classConsumere

温馨提示

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

评论

0/150

提交评论