多线程教学课件Java程序设计案例教程.pptx
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《多线程教学课件Java程序设计案例教程.pptx》由会员分享,可在线阅读,更多相关《多线程教学课件Java程序设计案例教程.pptx(113页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、多线程 教学课件Java程序设计案例教程7.1 线程概述人们在日常生活中,很多事情都是可以同时进行的。例如,一个人可以一边听音乐,一边打扫房间,可以一边吃饭,一边看电视。在使用计算机时,很多任务也是可以同时进行的。例如,可以一边浏览网页,一边打印文档,还可以一边聊天,一边复制文件等。7.1 线程概述计算机能够同时完成多项任务,例如,让浏览器执行0.001秒,让QQ执行0.001秒,这就是多线程技术。计算机中的CPU即使是单核也可以同时运行多个任务,因为操作系统执行多个任务时就是让CPU对多个任务轮流交替执行。Java是支持多线程的语言之一,它内置了对多线程技术的支持,可以使程序同时执行多个执行
2、片段。7.1.1 进程在学习线程之前,需要先了解什么是进程。在一个操作系统中,每个独立执行的程序都可称之为一个进程,也就是“正在运行的程序”。目前大部分计算机上安装的都是多任务操作系统,即能够同时执行多个应用程序,最常见的有Windows、Linux、Unix等。在本教材使用的Windows操作系统下,使用快捷键【Ctrl+Alt+Delete】,选择【启动任务管理器】选项可以打开任务管理器面板,在窗口的【进程】选项卡中可以看到当前在运行的程序,也就是系统所有的进程,如GoogleChrome、腾讯QQ等。7.1.1 进程任务管理器窗口如下图。7.1.1 进程在多任务操作系统中,表面上看是支持
3、进程并发执行的,例如可以一边听音乐一边聊天。但实际上这些进程并不是同时运行的。在计算机中,所有的应用程序都是由CPU执行的,对于一个CPU而言,在某个时间点只能运行一个程序,也就是说只能执行一个进程。操作系统会为每一个进程分配一段有限的CPU使用时间,CPU在这段时间中执行某个进程,然后会在下一段时间切换到另一个进程中去执行。由于CPU运行速度很快,能在极短的时间内在不同的进程之间进行切换,所以给人以同时执行多个程序的感觉。7.1.2 线程通过前面的学习可以知道,每个运行的程序都是一个进程,在一个进程中还可以有多个执行单元同时运行,这些执行单元可以看作程序执行的一条条路径,被称为线程。操作系统
4、中的每一个进程中都至少存在一个线程。例如当一个Java程序启动时,就会产生一个进程,该进程中会默认创建一个线程,在这个线程上会运行main()方法中的代码。7.1.2 线程在前面章节所接触过的程序中,代码都是按照调用顺序依次往下执行,没有出现两段程序代码交替运行的效果,这样的程序称作单线程程序。如果希望程序中实现多段程序代码交替运行的效果,则需要创建多个线程,即多线程程序。所谓的多线程是指一个进程在执行过程中可以产生多个单线程,这些单线程程序在运行时是相互独立的,它们可以并发执行。7.1.2 线程上图所示的多条线程,看似是同时执行的,其实不然,它们和进程一样,也是由CPU轮流执行的,只不过CP
5、U运行速度很快,故而给人同时执行的感觉。进程与线程是包含关系,但是多任务即可以由多线程实现,也可以由单进程内的多线程实现,还可以混合多进程+多线程。具体采用哪种方式,要考虑到进程和线程的特点。7.1.2 线程和多线程相比,多进程稳定性比多线程高,因为在多进程的情况下,一个进程崩溃不会影响其他进程,而在多线程的情况下,任何一个线程崩溃会直接导致整个进程崩溃。除此之外,多进程也有一些缺点,具体如下:创建进程比创建线程开销大,尤其是在Windows系统上。进程间通信比线程间通信要慢,因为线程间通信就是读写同一个变量,速度很快。7.2 多线程的创建在Java中提供了两种多线程实现方式,一种是继承jav
6、a.lang包下的Thread类,覆写Thread类的run()方法,在run()方法中实现运行在线程上的代码;另一种是实现java.lang.Runnable接口,同样是在run()方法中实现运行在线程上的代码。接下来就对创建多线程的两种方式分别进行讲解,并比较它们的优缺点。7.2.1 继承Thread类创建多线程在学习多线程之前,先看熟悉的单线程程序。7.2.1 继承Thread类创建多线程程序运行结果如下图。7.2.1 继承Thread类创建多线程从运行结果可以看出,程序一直打印“MyThread类的run()方法在运行”,这是因为该程序是一个单线程程序,第5行代码调用MyThread类
7、的run()方法时,遇到的是死循环,循环会一直进行。因此,MyThread类的打印语句将被无限执行,而main()方法中的打印语句无法得到执行。7.2.1 继承Thread类创建多线程如果希望程序中两个while循环中的打印语句能够并发执行,就需要实现多线程。为此Java提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。在Thread类中,提供了一个start()方法用于启动新线程,线程启动后,虚拟机会自动调用run()方法,如果子类重写了该方法便会执行子类中的方法。7.2.1 继承Thread类创建多线程将继承Thread类的多线程实
8、现步骤分为以下4步:(1)需要定义一个类,然后让这个类去继承Thread类,Thread类就是Java的线程类。(2)重写run方法。(3)创建定义的类的对象。(4)启动线程。7.2.1 继承Thread类创建多线程接下来,通过修改程序中的案例来演示如何通过继承Thread类的方式来实现多线程。7.2.1 继承Thread类创建多线程程序运行结果如下图。7.2.1 继承Thread类创建多线程上述代码利用两个while来模拟多线程环境,从运行结果,可以看到两个循环中的语句都有输出,说明该文件实现了多线程。7.2.1 继承Thread类创建多线程为了使读者更好地理解单线程和多线程的执行过程,接下
9、来通过一个图例分析一下单线程和多线程的区别。7.2.1 继承Thread类创建多线程从上图可以看出,单线程的程序在运行时,会按照代码的调用顺序执行,而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响,这正是单线程和多线程的区别。7.2.2 实现Runnable接口创建多线程通过继承Thread类可以实现多线程,但是这种方式有一定的局限性。因为Java只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,比如学生类Student继承了Person类,就无法通过继承Thread类创建线程。7.2.2 实现Runnable接口创建多线程为了克服这种
10、弊端,Thread类提供了另外一个构造方法Thread(Runnabletarget),其中Runnable是一个接口,它只有一个run()方法。当通过Thread(Runnabletarget)构造方法创建线程对象时,只需为该方法传递一个实现了Runnable接口的实例对象,这样创建的线程将调用实现了Runnable接口的类中的run()方法作为运行代码,而不需要调用Thread类中的run()方法。7.2.2 实现Runnable接口创建多线程我们可以将第二种创建多线程方式分为以下3步:(1)定义一个任务类,然后这个类去实现Runnable接口。Runnable接口就是一个任务接口,在该接
11、口中定义了一个方法,就是run方法,这个方法就是用来封装要被线程所执行的代码。(2)重写run方法。(3)创建Thread对象,在创建这个对象之前需要先创建任务类对象,然后把这个任务类对象作为Thread的构造方法参数传递过去。(4)启动线程。7.2.2 实现Runnable接口创建多线程接下来通过一个案例来演示如何通过实现Runnable接口的方式来创建多线程。7.2.2 实现Runnable接口创建多线程程序运行结果如下图。7.2.3 两种实现多线程方式的对比分析既然直接继承Thread类和实现Runnable接口都能实现多线程,那么这两种实现多线程的方式在实际应用中又有什么区别呢?接下来
12、通过一种应用场景来分析。假设售票厅有四个窗口可发售某日某次列车的100张车票,这时,100张车票可以看做共享资源,四个售票窗口需要创建四个线程。为了更直观显示窗口的售票情况,可以通过Thread的currentThread()方法得到当前的线程的实例对象,然后调用getName()方法可以获取到线程的名称。7.2.3 两种实现多线程方式的对比分析首先通过继承Thread类的方式创建多线程。7.2.3 两种实现多线程方式的对比分析程序运行结果如下图。7.2.3 两种实现多线程方式的对比分析上述程序中每个线程都有自己的名字,主线程默认的名字是“main”,用户创建的第一个线程的名字默认为“Thre
13、ad-0”,第二个线程的名字默认为“Thread-1”,以此类推。如果希望指定线程的名称,可以通过调用setName(Stringname)方法或者是构造方法为线程设置名称。接下来修改上述代码,利用构造方法的方式为每个线程设置名称:7.2.3 两种实现多线程方式的对比分析程序运行结果如下图。从运行结果可以看出,每张票都被打印了四次。出现这种现象的原因是四个线程没有共享100张票,而是各自出售了100张票。在程序中创建了四个TicketWindow对象,就等于创建了四个售票程序,每个程序中都有100张票,每个线程在独立地处理各自的资源。7.2.3 两种实现多线程方式的对比分析7.2.3 两种实现
14、多线程方式的对比分析由于现实中铁路系统的票资源是共享的,因此上面的运行结果显然不合理。所以说第一种方式售票是存在问题的,但是这个问题可不可以解决?也是可以解决的,将tickets被四个TicketWindow对象所共享就可以了,即将tickets前面使用static关键字修饰:7.2.3 两种实现多线程方式的对比分析下面使用多线程的第二种实现方式完成购票系统。为了保证资源共享,在程序中只创建一个售票对象,然后开启多个线程去运行同一个售票对象的售票方法。简单来说就是四个线程运行同一个售票程序。通过Runnable接口的方式来实现多线程的创建。修改上述程序,并使用构造方法Thread(Runnab
15、letarget,Stringname)在创建线程对象时指定线程的名称:7.2.3 两种实现多线程方式的对比分析7.2.3 两种实现多线程方式的对比分析程序运行结果如下图。7.2.3 两种实现多线程方式的对比分析上述程序中,第1021行代码创建了一个TicketWindow对象并实现Runnable接口,然后在main方法中创建了四个线程,在每个线程上都去调用这个TicketWindow对象中的run()方法,这样就可以确保四个线程访问的是同一个tickets变量,共享100张车票。7.2.3 两种实现多线程方式的对比分析这里tickets变量没有用static修饰,也能实现共享100张车票。
16、所以这两种实现多线程的方式的区别就可以看出来了。通过继承Thread类可以实现多线程,通过实现Runnable接口也可以实现多线程,实现Runnable接口相对于继承Thread类来说,具有以下优势:(1)适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。(2)可以避免由于Java的单继承带来的局限性。在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,因此不能使用继承Thread类的方式,只能采用实现Runnable接口的方式。7.2.3 两种实现多线程方式的对比分析小提示
17、:JDK8简化了多线程的创建方法,在创建线程时指定线程要调用的方法,格式如下。Thread t=new Thread()-/main方法代码 );7.2.3 两种实现多线程方式的对比分析下面我们通过一个案例来讲解,如下所示。7.2.3 两种实现多线程方式的对比分析运行结果如下:7.3 线程的生命周期及状态转换在Java中,任何对象都有生命周期,线程也不例外,它也有自己的生命周期。当Thread对象创建完成时,线程的生命周期便开始了。当run()方法中代码正常执行完毕或者线程抛出一个未捕获的异常(Exception)或者错误(Error)时,线程的生命周期便会结束。线程整个生命周期可以分为五个阶
18、段,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Terminated),线程的不同状态表明了线程当前正在进行的活动。7.3 线程的生命周期及状态转换在程序中,通过一些操作,可以使线程在不同状态之间转换。7.3 线程的生命周期及状态转换上图展示了线程各种状态的转换关系,箭头表示可转换的方向,其中,单箭头表示状态只能单向的转换,例如,线程只能从新建状态转换到就绪状态,反之则不能;双箭头表示两种状态可以互相转换,例如,就绪状态和运行状态可以互相转换。7.3 线程的生命周期及状态转换接下来针对线程生命周期中的五种状态分别进行
19、详细讲解,具体如下:1新建状态(New)创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其他Java对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征。2就绪状态(Runnable)当线程对象调用了start()方法后,该线程就进入就绪状态。处于就绪状态的线程位于线程队列中,此时它只是具备了运行的条件,能否获得CPU的使用权并开始运行,还需要等待系统的调度。简单来说,线程对象具有CPU的执行资格,但是没有获取CPU的使用权。7.3 线程的生命周期及状态转换3运行状态(Running)如果处于就绪状态的线程获得了CPU的使用权,并开始执行run()方法中的
20、线程执行体,则该线程处于运行状态。一个线程启动后,它可能不会一直处于运行状态,当运行状态的线程使用完系统分配的时间后,系统就会剥夺该线程占用的CPU资源,让其他线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才可能转换到运行状态。7.3 线程的生命周期及状态转换4阻塞状态(Blocked)一个正在执行的线程在某些特殊情况下,如被人为挂起或执行耗时的输入/输出操作时,会让出CPU的使用权并暂时中止自己的执行,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。7.3 线程的生命周期及状态转换下面就列举一下线程由运行状态转换成阻塞状态
21、的原因,以及如何从阻塞状态转换成就绪状态。当线程试图获取某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获取到其他线程所持有的锁。当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO方法返回。7.3 线程的生命周期及状态转换 当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程。当线程调用了Thread的sleep(longmillis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,
22、线程就会自动进入就绪状态。当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态。7.3 线程的生命周期及状态转换线程从阻塞状态只能进入就绪状态,而不能直接进入运行状态,也就是说结束阻塞的线程需要重新进入可运行池中,等待系统的调度。注 意7.3 线程的生命周期及状态转换5死亡状态(Terminated)当线程调用stop()方法或run()方法正常执行完毕后,或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程 教学课件Java程序设计案例教程 教学 课件 Java 程序设计 案例 教程
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内