第5章 多线程补充案例.docx
- 文档编号:7999660
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:22
- 大小:133.81KB
第5章 多线程补充案例.docx
《第5章 多线程补充案例.docx》由会员分享,可在线阅读,更多相关《第5章 多线程补充案例.docx(22页珍藏版)》请在冰豆网上搜索。
第5章多线程补充案例
第五章补充案例
案例5-1继承Thread类创建多线程
一、案例描述
1、考核知识点
编号:
00105002
名称:
继承Thread类创建多线程
2、练习目标
Ø掌握如何通过继承Thread类实现多线程的创建。
Ø掌握Thread类中run()方法和start()方法的使用。
3、需求分析
在程序开发中,会遇到一个功能需要多个线程同时执行才能完成的情况。
这时,可以通过继承线程类Thread,并重写Thread类中的run()方法来实现。
为了让初学者熟悉如何创建多线程,在案例中将通过继承Thread类方式创建线程,并实现多线程分别打印0~99的数字的功能。
4、设计思路(实现原理)
1)自定义一个类Demo,使其继承Thread类。
2)在Demo类中重写run()方法,在run()方法内编写一个for循环,循环体内打印:
“Demo:
”+当前循环次数。
3)编写测试类Example01,在Example01类的main()方法中,创建一个Demo对象,并执行其start()方法,接着编写一个for循环,循环体内打印:
“main:
”+当前循环次数。
二、案例实现
classDemoextendsThread{
publicvoidrun(){
for(intx=0;x<100;x++){
System.out.println("Demo:
"+x);
}
}
}
publicclassExample01{
publicstaticvoidmain(String[]args){
Demod=newDemo();
d.start();
for(intx=0;x<100;x++){
System.out.println("main:
"+x);
}
}
}
运行结果如图5-1所示。
图5-1运行结果
三、案例总结
1、通过继承Thread类,并重写Thread类中的run()方法可以实现多线程。
2、Thread类中,提供的start()方法用于启动新线程,线程启动后,系统会自动调用run()方法。
3、main()方法中有一条主线程在运行。
案例5-2实现Runnable接口创建多线程
一、案例描述
1、考核知识点
编号:
00105003
名称:
实现Runnable接口创建多线程
2、练习目标
Ø掌握如何通过实现Runnable接口方式创建多线程。
Ø掌握如何使用Thread类的有参构造方法创建Thread对象。
3、需求分析
在Java中只支持单继承,因此通过继承Thread类创建线程有一定的局限性,这时可以使用另一种方式,即实现Runnable接口来创建线程。
通过这种方式需要在Thread(Runnabletarget)的构造方法中,传递一个实现了Runnable接口的实例对象。
接下来在案例中将通过实现Runnable接口方式创建线程,并实现多线程分别打印0~99的数字的功能。
4、设计思路(实现原理)
1)自定义一个类Demo,使其实现Runnable接口。
2)在Demo类中覆写run()方法,在方法编写一个for循环,循环体内打印:
当前线程名称:
+当前循环次数。
3)编写测试类Example02,在Example02类的main()方法中,创建一个Demo对象,利用Thread(Runnabletarget)构造方法创建2个线程对象,分别命名为“蜘蛛侠”和“钢铁侠”,并执行线程对象的start()方法,同时编写for循环,循环内打印“main:
”+当前循环次数。
二、案例实现
classDemoimplementsRunnable{
publicvoidrun(){
for(intx=0;x<100;x++){
System.out.println(Thread.currentThread().getName()+":
"+x);
}
}
}
publicclassExample02{
publicstaticvoidmain(String[]args){
Demod=newDemo();
Threadt1=newThread(d,"蜘蛛侠");
Threadt2=newThread(d,"钢铁侠");
t1.start();
t2.start();
for(intx=0;x<100;x++){
System.out.println("main:
"+x);
}
}
}
运行结果如图5-2所示。
图5-2运行结果
三、案例总结
1、可以把实现了Runnable接口并重写run()方法的实例对象,作为Thread有参构造方法的参数来创建多线程程序。
2、使用Thread类的构造方法Thread(Runnable target,String name)创建线程对象时,还可以给线程指定新名称。
3、思考一下:
既然有了继承Thread类的方式,为什么还要有实现Runnable接口的方式?
a)可以避免由于Java的单继承带来的局限性。
在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么就只能采用实现Runnable接口的方式。
b)实现接口的方式,适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。
例如:
一个售票程序继承了Thread类,在售票时启动了多个售票程序,但他们不是同一个对象,数据没有共享,这样就会出现票数重复出售的情况;而当售票程序实现Runnable接口后,多个线程运行同一个售票程序,实现了票数共享的好处。
案例5-3设置后台线程
一、案例描述
1、考核知识点
编号:
00105005
名称:
后台线程
2、练习目标
Ø了解后台线程的生命周期
Ø掌握如何将线程设置为后台线程
3、需求分析
默认情况下,新创建的线程都是前台线程,若想使前台线程变为后台线程,可以使用setDaemon(true)方法实现,为了让初学者熟悉后台线程,案例中将通过设置一个后台线程并演示后台线程和程序结束之间的关系。
4、设计思路(实现原理)
1)自定义一个类Watcher,使其实现Runnable接口。
2)在Watcher类中覆写run()方法,在方法内编写一个for循环,循环体内打印:
线程名称+循环次数。
3)编写测试类Example03,在Example03类的main()方法中,创建一个Watcher对象,利用Thread(Runnabletarget)构造方法创建线程对象并命名,将线程设置为后台线程,执行该线程的start()方法,接着编写一个for循环,循环内打印循环次数。
二、案例实现
classWatcherimplementsRunnable{
publicvoidrun(){
for(intx=0;x<1000;x++){
System.out.println("我是"+Thread.currentThread().getName()
+"守护者,"+"我在守护雅典娜"+x);
}
}
}
publicclassExample03{
publicstaticvoidmain(String[]args){
Watcherwatcher=newWatcher();
Threadt=newThread(watcher,"星矢");
t.setDaemon(true);
t.start();
for(inti=3;i>0;i--){
System.out.println("我是雅典娜女神,我马上死了!
"+i);
if(i==1){
System.out.println("我是雅典娜女神,我死了!
");
}
}
}
}
运行结果如图5-3所示。
图5-3运行结果
三、案例总结
1、在多线程程序中,一旦前台线程(例如主线程)结束,后台线程也就结束了。
2、要将某个线程设置为后台线程,该线程的setDaemon()方法必须在start()方法之前调用,否则会引发IllegalThreadStateException异常。
案例5-4线程的优先级
一、案例描述
1、考核知识点
编号:
00105007
名称:
线程的优先级
2、练习目标
Ø了解线程中优先级的概念和作用
Ø掌握设置线程优先级的方法
Ø掌握线程设置优先级方法中的三个静态常量
3、需求分析
在应用程序中,如果要对线程进行调度,最直接的方式就是设置线程的优先级。
这时,可以通过线程的setPriority()方法来设置线程优先级别,实现对线程的调度功能。
为了让初学者掌握线程的优先级,在案例中创建3个线程,分别为它们设置不同的优先级来演示不同优先级线程的调度。
4、设计思路(实现原理)
1)自定义一个类Demo,使其实现Runnable接口。
2)在Demo类中重写run()方法,在方法内编写一个for循环,循环体内打印:
线程名称+循环次数。
3)编写测试类Example04,在Example04类的main()方法中,创建一个Demo对象,利用Thread的构造方法创建三个线程对象并命名,使用setPriority()方法将其中两个线程的优先级设为最大和最小,最后开启三个线程的start()方法。
二、案例实现
classDemoimplementsRunnable{
publicvoidrun(){
for(intx=0;x<5;x++){
System.out.println(Thread.currentThread().getName()+"---"+x);
}
}
}
publicclassExample04{
publicstaticvoidmain(String[]args){
Demod=newDemo();
Threadt1=newThread(d,"杨过");
Threadt2=newThread(d,"岳不群");
Threadt3=newThread(d,"金龙");
//设置线程的优先级
t3.setPriority(Thread.MAX_PRIORITY);
t2.setPriority
(1);
t1.start();
t2.start();
t3.start();
}
}
运行结果如图5-4所示。
图5-4运行结果
三、案例总结
1、在多线程程序中,可以通过设置线程的优先级别来控制线程获得CPU执行的几率。
2、线程的优先级用1~10之间的整数来表示,数字越大优先级越高。
也可以使用静态常量表示线程的优先级,如:
MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY。
3、虽然Java中提供了10个线程优先级,但是这些优先级需要操作系统的支持,不同的操作系统对优先级的支持是不一样的,不能很好的和Java中线程优先级一一对应,因此,在设计多线程应用程序时,其功能的实现一定不能依赖于线程的优先级,而只能把线程优先级作为一种提高程序效率的手段。
案例5-5线程休眠
一、案例描述
1、考核知识点
编号:
00105008
名称:
线程休眠
2、练习目标
Ø了解线程休眠的概念和作用
Ø掌握如何使用sleep(longmillis)方法使线程休眠
3、需求分析
如果希望人为地控制线程,使正在执行的线程暂停,将CPU让给别的线程。
这时,可以使用静态方法sleep(longmillis),该方法可以让当前正在执行的线程暂停一段时间,进入休眠等待状态。
为了让初学者更好地掌握线程休眠,案例中将启动三个线程共同出售10张票来演示线程休眠及休眠引发的结果。
4、设计思路(实现原理)
1)自定义一个类Ticket,使其实现Runnable接口,并在该类中创建int类型私有属性tickets,赋初值为10。
2)在Ticket类中重写run()方法,在方法内编写一个while循环。
循环体内判断ticket值,当大于0时,使用sleep(longmillis)方法使线程休眠1秒钟,并打印:
当前线程名称+“正在出售第”+循环次数;否则结束循环。
每执行一次while循环,tickets值减一。
3)编写测试类Example05,在Example05类的main()方法中,创建一个Ticket对象,利用Thread的构造方法创建三个线程对象并命名,并开启三个线程的start()方法。
二、案例实现
classTicketimplementsRunnable{
privateinttickets=10;
publicvoidrun(){
while(true){
if(tickets>0){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+"正在出售第"+(tickets--)+"张票");
}
}
}
}
publicclassExample05{
publicstaticvoidmain(String[]args){
Tickettr=newTicket();
Threadt1=newThread(tr);
Threadt2=newThread(tr);
Threadt3=newThread(tr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果如图5-5所示。
图5-5运行结果
从运行结果可以看出,当程序启动后,“窗口1”、“窗口2”、“窗口3”线程共同出售tikcets,但是最后“窗口1”出售了第0张票、“窗口3”出售了第-1张票,从中可以推断当tickets=1时,某一个线程进入if分支语句后,线程休眠了1秒。
在此期间,tickets的值依然为1,其他两个线程也顺利进入了到if分支语句中,当线程休眠时间结束后,三个线程分别操作了ticket值,所以造成了tickets值为负数。
三、案例总结
1、sleep(longmillis)方法声明抛出InterruptedException异常,因此在调用该方法时应该捕获异常,或者声明抛出该异常。
2、sleep()是静态方法,只能控制当前正在运行的线程休眠,而不能控制其它线程休眠。
当休眠时间结束后,线程就会返回到就绪状态,而不是立即开始运行。
案例5-6线程让步
一、案例描述
1、考核知识点
编号:
00105009
名称:
线程让步
2、练习目标
Ø了解线程让步的概念和作用
Ø掌握设置线程让步的方法
3、需求分析
在校园中,我们经常会看到同学互相抢篮球,当某个同学抢到篮球后就可以拍一会,之后他会把篮球让出来,大家重新开始抢篮球,这个过程就相当于Java程序中的线程让步。
在多线程程序中,可以通过线程的yield()方法将线程转换成就绪状态,让系统的调度器重新调度一次,达到线程让步的目的。
案例中将在一个多线程程序中,通过yield()方法对其中一个线程设置线程让步来演示。
4、设计思路(实现原理)
1)自定义一个类Demo,使其实现Runnable接口。
2)在Demo类中覆写run()方法,在方法内编写一个for循环,循环体内,先执行线程让步的方法yield(),然后输出打印:
线程名称+循环次数。
3)编写测试类Example06,在Example06类的main()方法中,创建一个Demo对象,利用Thread的构造方法创建两个线程对象,并执行线程对象的start()方法,同时编写for循环,循环内打印“main:
”+当前循环次数。
二、案例实现
classDemoimplementsRunnable{
publicvoidrun(){
for(intx=0;x<5;x++){
Thread.yield();
System.out.println(Thread.currentThread().getName()+"..."+x);
}
}
}
publicclassExample06{
publicstaticvoidmain(String[]args)throwsException{
Demod=newDemo();
Threadt0=newThread(d);
Threadt1=newThread(d);
t0.start();
t1.start();
for(intx=0;x<5;x++){
System.out.println("main..."+x);
}
}
}
运行结果如图5-6所示。
图5-6运行结果
三、案例总结
1、在多线程程序中,可以通过设置线程让步,让系统的调度器重新调度一次CPU的分配。
2、线程让步和线程休眠是不一样的,线程让步不会阻塞该线程,它只是将线程转换成就绪状态,而线程休眠,是让线程在一定时间内进入休眠等待状态,到达时间后线程再转换成就绪状态。
案例5-7线程插队
一、案例描述
1、考核知识点
编号:
00105010
名称:
线程插队
2、练习目标
Ø了解线程插队的概念和作用
Ø掌握线程插队方法的使用
3、需求分析
在火车站买票的时候,有的乘客着急赶火车,会插到队伍前面先买车票,其他乘客再买票。
那么在多线程程序中,也可以通过线程插队,让插队的线程先执行完,然后本线程才开始执行。
在案例中将通过使用join()方法来演示线程插队。
4、设计思路(实现原理)
1)自定义一个类Demo,使其实现Runnable接口。
2)在Demo类中覆写run()方法,在方法内编写一个for循环,循环体内打印:
线程名称+循环次数。
3)编写测试类Example07,在Example07类的main()方法中,创建一个Demo对象,利用Thread的构造方法创建两个线程对象,分别命名“排队队员”和“插队队员”,然后编写两个线程对象的start()方法,然后调用“插队队员”线程的join()方法。
二、案例实现
classDemoimplementsRunnable{
publicvoidrun(){
for(intx=0;x<5;x++){
System.out.println(Thread.currentThread().getName()+"---"+x);
}
}
}
publicclassExample07{
publicstaticvoidmain(String[]args){
Demojd=newDemo();
Threadt1=newThread(jd);
Threadt2=newThread(jd);
t1.setName("排队队员");
t2.setName("插队队员");
t1.start();
t2.start();
try{
t2.join();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
运行结果如图5-7所示。
图5-7运行结果
三、案例总结
1、线程插队,可以让插队的线程先执行完,然后本线程才开始执行。
2、使用线程插队join()方法时,需要抛出InterruptedException异常。
案例5-8同步代码块的使用
一、案例描述
1、考核知识点
编号:
00105012
名称:
同步代码块
2、练习目标
Ø掌握同步代码块作用
Ø掌握同步代码块的使用方法
Ø掌握同步代码块中锁对象的使用
3、需求分析
生活中,会遇到两人上洗手间的问题,甲使用洗手间的时候会锁上门,乙看到门锁上了,就需要等甲使用完后再使用的。
那么在多线程程序中,可以通过将共享资源放在同步代码块内来实现多个线程同步处理共享资源的问题。
本案例将通过两个线程共享资源来演示同步代码块的使用。
4、设计思路(实现原理)
1)自定义一个类Demo,使其实现Runnable接口。
2)在Demo类中覆写run()方法,在方法内编写synchronized同步代码块,在进入同步代码块时,打印线程名称,然后编写一个for循环,循环体内打印:
运行线程名称+循环次数。
当循环次数等于3时,跳出循环。
3)编写测试类Example08,在Example08类的main()方法中,创建一个Demo对象,利用Thread的构造方法创建两个线程对象,分别命名“张三”和“李四”,执行两个线程的start()方法。
二、案例实现
classDemoimplementsRunnable{
privateObjectobj=newObject();
publicvoidrun(){
synchronized(obj){
System.out.println(Thread.currentThread().getName()
+"进入洗手间,门以锁上");
for(inti=1;i<10;i++){
System.out.println(Thread.currentThread().getName()
+"正在使用洗手间"+i);
if(i==3){
System.out.println(Thread.currentThread().getName()
+"用完,准备出去,锁打开");
break;
}
}
}
}
}
publicclassExample08{
publicstaticvoidmain(String[]args){
Demod=newDemo();
Threadt1=newThread(d,"张三");
Threadt2=newThread(d,"李四
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第5章 多线程补充案例 多线程 补充 案例