Java程序设计PPT课件版 第八章 多线程_第1页
Java程序设计PPT课件版 第八章 多线程_第2页
Java程序设计PPT课件版 第八章 多线程_第3页
Java程序设计PPT课件版 第八章 多线程_第4页
Java程序设计PPT课件版 第八章 多线程_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

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

文档简介

第六章多线程授课教师:高成珍QQ:1281147324进程和线程综合示例线程的互斥和同步线程的状态和生命周期创建线程的两种方式本章主要内容能够自主实现多线程示例理解线程的互斥和同步熟练掌握创建线程的两种方式

熟练掌握线程状态间的转化

本章重点与难点理解和掌握进程和线程的概念进程和线程几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程(Process)。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程(Thread)。进程与线程的区别1、进程拥有自己独立的资源,线程不拥有资源,它与父进程的其他线程共享该进程所拥有的全部资源;2、创建或撤销一个进程所需要的开销比创建或撤销一个线程所需要的开销大;3、进程为重量级组件,线程为轻量级组件;任务1任务2任务3多线程在多个CPU上运行多线程分享单个CPU任务1任务2任务3并行和并发

并行(Parallel)指在同一时刻,有多条指令在多个处理器上同时执行;

并发(concurrency)指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。线程类介绍(Thread)

publicstaticThreadcurrentThread():返回当前执行的线程对象;publicfinalStringgetName():返回该线程的名称;publicfinalvoidsetPriority(int

newPriority):更改线程的优先级。publicThread.State

getState():返回该线程的状态。publicvoidstart():使该线程开始执行,多次启动一个线程是非法的;publicstaticvoidsleep(long

millis)throwsInterruptedException在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。publicstaticvoidyield():暂停当前正在执行的线程对象,并执行其他线程。构造方法:Thread()、Thread(Stringname)、Thread(Runnabletarget)线程的创建和启动定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务;创建Thread子类的实例,即创建线程对象;调用线程对象的start()方法启动该线程。1、继承Thread类创建线程类

在Java中,程序入口被自动创建为主线程,main()方法的方法体就是主线程的线程执行体。

启动线程使用start()方法,而不是run()方法!如果直接调用run()方法,系统会把线程对象当成一个普通对象,而run()方法也是一个普通方法,而不是线程执行体。线程的创建和启动定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体即该线程的线程执行体;创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;调用线程对象的start()方法启动该线程。2、实现Runnable接口创建线程第一种方式只能在类没有继承其它任何类的情况下才能使用?,如果一个类要继承其它的类,最好选用第二种方法,这样有更好的灵活性。线程的生命周期1、新建和就绪状态当程序使用new关键字创建一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。当调用线程对象的start()方法之后,该线程就处于就绪状态,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了。至于该线程何时开始运行,取决于JVM里线程调度器的调度。在线程的生命周期中,要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。线程启动以后,不可能一直霸占着CPU独自运行,CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。线程的生命周期2、运行和阻塞状态如果处于就绪状态的线程获得了CPU,开始执行run()方法,则该线程处于运行状态,线程在运行过程中会被中断,目的是使其他线程获得执行的机会,线程调度的细节取决于底层平台所采用的策略。当发生如下情况时,线程会进入阻塞状态线程调用sleep()方法主动放弃所占用的处理器资源;线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞;线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有;线程在等待某个通知(notify);线程的生命周期被阻塞的线程会在合适的时候重新进入就绪状态,注意不是运行状态。被阻塞线程的阻塞解除后,必须重新等待线程调度器再次调度它。当发生如下情况时,可解除阻塞,让线程重新进入就绪状态。调用sleep()方法的线程经过了指定时间;线程调用的阻塞式IO方法已经返回;线程成功地获得了试图取得的同步监视器;线程正在等待某个通知时,其他线程发出了一个通知;2、运行和阻塞状态线程的生命周期run()方法执行完成,线程正常结束;线程抛出一个未捕获的Exception或Error;直接调用该线程的stop()方法来结束该线程。注意:当主线程结束时,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位。3、线程死亡为了测试某个线程是否已经死亡,可以调用线程对象的isAlive()方法,当线程处于就绪、运行、阻塞3种状态时,该方法将返回true;当线程处于新建、死亡2中状态时,该方法将返回false。线程状态转换图线程状态转换图控制线程如果需要当前正在执行的线程暂停一段时间,并进入阻塞状态,可通过调用Thread类的静态方法sleep()方法来实现。即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行,sleep()方法常用来暂停程序的执行。1、线程睡眠(sleep)

Thread提供了让一个线程等待另一个线程完成的方法—join()方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法join线程执行完为止。2、join线程控制线程有一种线程,它是在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为“后台线程”,也叫“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。3、后台线程(Daemon)调用Thread对象的setDaemon(true)方法可将指定线程设置为后台线程,通过isDaemon()方法,可判断指定线程是否为后台线程。当要将某个线程设置为后台线程时,必须要在该线程启动之前,否则会引发IllegalThreadStateException异常。控制线程

yield()方法和sleep()方法相似,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。即让系统的线程调度器重新调度一次。完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。4、线程让步(yield)当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。控制线程

sleep()方法和yield()方法的区别:sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同,或优先级更高的线程执行机会;sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态;sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要慢捕捉该异常,要么显示声明抛出该异常;而yield()方法则没有声明抛出任何异常;模拟账户存取钱

银行账户类,提供相关属性的setter和getter方法操作线程类的构造方法,传入需要操作的账户、具体的操作以及操作的金额模拟账户存取钱线程执行体测试方法模拟账户存取钱多线程操作时,会存在余额为负数的情况,为什么会这样,如何解决?线程同步为了解决多个线程对共享资源的操作而导致的数据不一致问题,Java的多线程支持引入了同步监视器,使用关键字synchronized。线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。通用方法就是同步代码块,语法格式如下:synchronized(obj){ … //此处的代码就是同步代码块}注意:任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定。同步方法同步方法与同步代码块相似,需要使用synchronized关键字修饰,对于同步方法而言,无须显示指定同步监视器,同步方法的同步监视器是this,即当前对象本身。通过使用同步方法可方便实现线程安全的类,线程安全的类具有如下特征:该类的对象可以被多个线程安全地访问;每个线程调用该对象的任意方法后都将得到正确结果;每个线程调用该对象的任意方法后,该对象状态依然保持合理状态。

不可变类总是线程安全的,因为它的对象状态不可改变;但可变对象需要额外的方法(同步方法)来保证线程安全,这是以降低程序的运行效率为代价的。通常只对那些会改变共享资源的方法进行同步。释放同步监视器任何线程进入同步代码块、同步方法之前,必须先获得对同步监视器的锁定,那么何时会释放对同步监视器的锁定呢?当前线程的同步方法、同步代码块执行结束,即释放同步监视器;当前线程在同步方法、同步代码块中遇到break、return终止了该代码块、该方法的继续执行,将会释放同步监视器;当前线程在同步方法、同步代码块中出现了未处理的Error或Exception,导致代码块或方法异常结束时,会释放同步监视器;当前线程执行同步代码块或同步方式时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器。注意:当同步代码块或同步方法中,调用Thread.sleep()、Thread.yield()方法来暂停当前线程的执行,当前线程不会释放同监视器。同步监视器引起的死锁问题

Java线程死锁是一个经典的多线程问题,是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。导致死锁必须满足以下条件:互斥,即多个线程不能同时使用同一资源;占有等待,即某个线程必须同时拥有几个资源才能执行完成;非剥夺,即资源只能由线程执行完主动释放,而不能在别的线程没有释放资源的情况下,夺走其已占有的资源;环路等待条件:你等待我释放资源,我等待你释放资源,资源没有满足的线程无限期地等待。例如有两个人A和B,面前摆放着食物,需要同时使用刀和叉才能食用,但现在只有一副刀叉,A获得了刀,B获得了叉。A在等待获得叉,B在等待获得刀。谁也不愿意给对方,这时候就进入僵持状态即死锁状态。模拟死锁的关键代码程序执行入口,主方法线程方法执行体生产者消费者问题解决方案:让生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据时,生产者才能被唤醒,开始往缓冲区添加数据。同样,让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据后,再唤醒消费者。

温馨提示

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

评论

0/150

提交评论