您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业文化 > Java基础第5章课件解析
让IT教学更简单,让IT学习更有效让IT教学更简单,让IT学习更有效第五章多线程•多线程的概念•线程创建的两种方式•线程的生命周期及状态转换•线程的调度•线程的安全和同步•多线程通信让IT教学更简单,让IT学习更有效目录线程概述线程的创建线程的生命周期及状态转换线程的调度多线程同步多线程通信让IT教学更简单,让IT学习更有效5.1线程概述•5.1.1进程–在一个操作系统中,每个独立执行的程序都可称之为一个进程,也就是“正在运行的程序”。–目前大部分计算机上安装的都是多任务操作系统,即能够同时执行多个应用程序。–在计算机中,所有的应用程序都是由CPU执行的,对于一个CPU而言,在某个时间点只能运行一个程序,也就是说只能执行一个进程。让IT教学更简单,让IT学习更有效5.1线程概述•5.1.2线程–每个运行的程序都是一个进程,在一个进程中还可以有多个执行单元同时运行,这些执行单元可以看做程序执行的一条条线索,被称为线程。–操作系统中的每一个进程中都至少存在一个线程。当一个Java程序启动时,就会产生了一个进程,该进程中会默认创建一个线程,在这个线程上会运行main()方法中的代码。让IT教学更简单,让IT学习更有效5.1线程概述•5.1.2线程–前面章节所接触过的程序中,代码都是按照调用顺序依次往下执行,没有出现两段程序代码交替运行的效果,这样的程序称作单线程程序。–如果希望程序中实现多段程序代码交替运行的效果,则需要创建多个线程,即多线程程序。多线程程序在运行时,每个线程之间都是独立的,它们可以并发执行。程序线程2线程3线程1让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–单线程程序让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–运行结果–结果可以看出,程序一直打印的是“MyThread类的run()方法在运行”,这是因为该程序是一个单线程程序,当调用MyThread类的run()方法时,遇到死循环,循环会一直进行。–如果希望例程5-1中两个while循环中的的打印语句能够并发执行,就需要实现多线程。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–JDK中提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。–在Thread类中,提供了一个start()方法用于启动新线程,线程启动后,系统会自动调用run()方法,如果子类重写了该方法便会执行子类中的方法。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–通过继承Thread类的方式来实现多线程让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–运行结果–两个while循环中的打印语句轮流执行了,说明该例程实现了多线程让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.1继承Thread类创建多线程–单线程的程序在运行时,会按照代码的调用顺序进行执行。而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响,这正是单线程和多线程的区别。Example01.main()MyThread.run()单线程Example01.main()多线程MyThread.run()while语句打印语句while语句打印语句让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.2实现Runnable接口创建多线程–通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类–Thread类提供了另外一个构造方法Thread(Runnabletarget),其中Runnable是一个接口,它只有一个run()方法。当通过Thread(Runnabletarget))构造方法创建线程对象时,只需为该方法传递一个实现了Runnable接口的实例对象,这样创建的线程将调用实现了Runnable接口中的run()方法作为运行代码,而不需要调用Thread类中的run()方法让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.2实现Runnable接口创建多线程–实现Runnable接口创建多线程让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.2实现Runnable接口创建多线程–运行结果–MyThread类实现了Runnable接口,并重写了Runnable接口中的run()方法,通过Thread类的构造方法将MyThread类的实例对象作为参数传入。从运行结果可以看出,main()方法和run()方法中的打印语句都执行了,说明例程实现了多线程。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.3两种实现多线程方式的对比分析–假设售票厅有四个窗口可发售某日某次列车的100张车票,这时,100张车票可以看做共享资源,四个售票窗口需要创建四个线程,为了更直观显示窗口的售票情况,可以通过Thread的currentThread()方法得到当前的线程的实例对象,然后调用getName()可以获取到线程的名称。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.3两种实现多线程方式的对比分析–通过继承Thread类的方式来实现多线程的创建让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.3两种实现多线程方式的对比分析–运行结果–可以看出,每张票都被打印了四次。出现这样现象的原因是四个线程没有共享100张票,而是各自出售了100张票。在程序中创建了四个TicketWindow对象,就等于创建了四个售票程序,每个程序中都有100张票,每个线程在独立地处理各自的资源。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.3两种实现多线程方式的对比分析–为了保证资源共享,在程序中只能创建一个售票对象,然后开启多个线程去运行这同一个售票对象的售票方法,简单来说就是四个线程运行同一个售票程序,这时就需要用到多线程的第二种实现方式。–将例程5-4进行修改,并使用构造方法Thread(Runnabletarget,Stringname)在创建线程对象的同时指定线程的名称。•只创建了一个TicketWindow对象,然后创建了四个线程,在每个线程上都去调用这个TicketWindow对象中的run()方法,这样就可以确保四个线程访问的是同一个tickets变量,共享100张车票。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.3两种实现多线程方式的对比分析–实现Runnable接口相对于继承Thread类来说,有如下显著好处:•1、适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码、数据有效的分离,很好的体现了面向对象的设计思想。•2、可以避免由于Java的单继承带来的局限性。在开发中经常碰到这样一种情况,就是使用一个已经继承了某一个类的子类创建线程,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么就只能采用实现Runnable接口的方式。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.4后台线程–对Java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。这里提到的前台线程和后台线程是一种相对的概念,新创建的线程默认都是前台线程,如果某个线程对象在启动之前调用了setDaemon(true)语句,这个线程就变成一个后台线程。让IT教学更简单,让IT学习更有效5.2线程的创建•5.2.4后台线程•当开启线程t后,会执行死循环中的打印语句,但我们将线程t设置为后台线程后,当前台线程死亡后,JVM会通知后台线程。由于后台线程从接受指令,到作出响应,需要一定的时间,因此,打印了几次“后台线程---isrunning.”语句后,后台线程也结束了。由此说明进程中只有后台线程运行时,进程就会结束。让IT教学更简单,让IT学习更有效5.3线程的生命周期及状态转换–线程整个生命周期可以分为五个阶段,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Terminated),线程的不同状态表明了线程当前正在进行的活动。–线程各种状态的转换关系,箭头表示可转换的方向,其中,单箭头表示状态只能单向的转换,比如线程只能从新建状态转换到就绪状态,反之则不能,双箭头表示两种状态可以互相转换,比如就绪状态和运行状态可以互相转换。新建状态就绪状态运行状态阻塞状态死亡状态start()获得CPU使用权失去CPU使用权等待同步锁调用IO阻塞方法调用wait()方法调用join()方法调用sleep()方法获得同步锁阻塞IO方法返回调用notify()方法调用join()的线程终止sleep()时间到run()执行完Exception或Error让IT教学更简单,让IT学习更有效•1、新建状态(New)创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其它Java对象一样,仅仅由Java虚拟机为其分配了内存,没有表现出任何线程的动态特征。•2、就绪状态(Runnable)当线程对象调用了start()方法后,该线程就进入就绪状态(也称可运行状态)。处于就绪状态的线程位于可运行池中,此时它只是具备了运行的条件,能否获得CPU的使用权开始运行,还需要等待系统的调度。5.3线程的生命周期及状态转换让IT教学更简单,让IT学习更有效•3、运行状态(Running)如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态。当一个线程启动后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就结束了),当使用完系统分配的时间后,系统就会剥夺该线程占用的CPU资源,让其它线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才可能转换到运行状态。•4、阻塞状态(Blocked)一个正在执行的线程在某些特殊情况下,如执行耗时的输入/输出操作时,会放弃CPU的使用权,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。5.3线程的生命周期及状态转换让IT教学更简单,让IT学习更有效•当线程试图获取某个对象的同步锁时,如果该锁被其它线程所持有,则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态必须得获取到其它线程所持有的锁。•当线程调用了一个阻塞式的IO方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO方法返回。•当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程。5.3线程的生命周期及状态转换让IT教学更简单,让IT学习更有效•当线程调用了Thread的sleep(longmillis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,线程就会自动进入就绪状态。•当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态。•5、死亡状态(Terminated)线程的run()方法正常执行完毕或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入死亡状态。一旦进入死亡状态,线程将不再拥有运行的资格,也不能再转换到其它状态。5.3线程的生命周期及状态转换让IT教学更简单,让IT学习更有效5.4线程的调度•5.4.1线程的优先级–优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。–线程的优先级用1~10之间的整数来表示,数字越大优先级越高
本文标题:Java基础第5章课件解析
链接地址:https://www.777doc.com/doc-6156988 .html