Java面向对象程序设计案例教程(第二版) 课件 第10章 多线程_第1页
Java面向对象程序设计案例教程(第二版) 课件 第10章 多线程_第2页
Java面向对象程序设计案例教程(第二版) 课件 第10章 多线程_第3页
Java面向对象程序设计案例教程(第二版) 课件 第10章 多线程_第4页
Java面向对象程序设计案例教程(第二版) 课件 第10章 多线程_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

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

文档简介

第10章多线程《Java面向对象程序设计案例教程(第2版)》目录/Contents10.110.210.3线程基础与创建线程生命周期与操作线程同步与安全10.4

多线程性能优化10.5

多线程实践案例思政要点/Point团队合作

培养学生的团队合作精神和协同工作的能力,确保多线程环境中的有效沟通和协作。性能优化

提升资源管理和优化意识,提高多线程系统的整体性能。信息安全

提升法律意识和信息安全意识,确保多线程环境中的数据安全。创新思维

激发创新精神和持续学习的动力,关注多线程技术的最新发展。线程基础与创建10.1

线程就是在某种程度上相互隔离的、独立运行的程序。线程化是允许多个活动共存于一个进程的工具。大多数现代操作系统都支持线程,而且线程的概念以各种形式已存在了很多年。Java是第一个在语言本身中显式地包含线程的主流编程语言,它没有把线程化看作是底层操作系统工具。10.1.1线程的概念

每个Java程序都至少有一个线程——主线程。当一个Java程序启动时,JVM会创建主线程,并在该线程中调用程序的main()方法。JVM还创建了其他线程,但通常都看不到,例如与垃圾收集、对象中止和其他JVM内务处理任务相关的线程。其他工具也创建线程,如抽象窗口工具包(AWT)或SwingUI工具包、Servlet容器、应用程序服务器和远程方法调用(RMI)。图10-1所示为线程全部运行的状态图。10.1.2Java中的线程图10-1

线程状态转化图

使用线程的原因是它们可以使UI响应更快、利用多处理系统、简化建模。执行异步或后台处理、响应更快UI事件驱动的UI工具箱(如AWT和Swing)有一个时间线程,它处理UI事件,如按键或鼠标单击。SWT和Swing程序把事件监听器与UI对象连接。当特定事件(如单击按钮)发生时,这些监听器会得到通知。事件监听器是AWT事件线程中调用的。

如果事件监听器要执行持续很久的任务,如检查一个大文档中的拼写,事件线程将忙于运行拼写检查器,所以在完成事件监听器之前,就不能处理额外的UI事件。这就会使程序看起来似乎停滞了,让用户不知所措。要避免使UI延迟响应,事件监听器应该把较长的任务放到另一个编程中,这样AWT线程在任务的执行过程中就可以继续处理UI事件(包括取消正在执行的长时间运行任务的请求)。10.1.3使用线程的原因线程创建10.2

继承java.lang.Thread类,重写publicvoidrun()方法。示例代码如下:publicclassThread1extendsThread{//继承Thread类并重写run方法//该方法中重写在当前线程中需要运行的代码publicvoidrun(){for(inti=0;i<1000;i++){System.out.println(i);}}}10.2.1继承java.lang.Thread类创建线程的第一种方式实现java.lang.Runnable接口,实现run()方法。代码如下:publicclassRun1implementsRunnable{publicvoidrun(){for(inti=0;i<1000;i++){System.out.println(i);}}}

这种线程启动时和第一种方式不同,需要通过下面的代码完成:Run1run1=newRun1();Threadt1=newThread(run1);t1.start();10.2.2实现java.lang.Runnable接口创建线程的第二种方式线程的生命周期10.310.3.1创建和就绪状态

当我们用new运算符以后,就创建了一个线程的实例,创建完成以后该线程就处于新建状态,此时它就被Java虚拟机分配内存,并且会初始化其成员变量的值。此时线程只是处于实例状态,并不会执行线程体。当线程对象调用了start()方法之后,该线程就处于就绪状态,Java虚拟机会为其创建方法调用的栈,但是该线程只是处于就绪状态,并不会开始执行,只是代表该线程可以运行了,至于何时运行,取决于JVM里调度器的调度。10.3.2运行和阻塞状态

当一个线程开始运行后,它不可能一直处于运行状态,线程在运行过程中需要被中断,目的是让其他线程获得执行的机会。线程调度的细节取决于底层调度策略,系统会为每个线程分配一个微小的时间片段来处理任务,当时间用完后,系统会剥夺该线程所占用的资源,给其他线程执行的机会,至于下一个让哪个线程执行,会考虑线程的优先级。当出现下面的情况时,线程会进入阻塞状态。1.线程调用了sleep()方法。2.线程调用了一个阻塞的I/O方法,在该方法返回之前,线程被阻塞。3.线程在等待某个通知(notify)。

程序调用了线程的suspend()方法,将该线程挂起。10.3.3线程死亡

线程出现以下几种情况就会自动结束,结束后的线程处于死亡状态。1. run()方法执行完成,线程正常结束。2.线程出现了Exception或Error。3.直接调用了线程的stop()方法结束线程。如果想测试某个线程是否已经死亡,则可以调用线程的isAlive()方法。当线程处于就绪、运行、阻塞状态时,该方法将返回true;当线程处于新建、死亡状态时,该方法返回false。线程操作10.410.4.1join线程publicclassJoinThreadDemoextendsThread{//设置线程名publicJoinThreadDemo(Stringname){super(name);}//线程体publicvoidrun(){for(inti=0;i<100;i++){System.out.println(getName()+":"+i);}}publicstaticvoidmain(String[]args){//主线程开始for(inti=0;i<100;i++){if(i==20){//子线程被创建join线程使用示例JoinThreadDemodemo=newJoinThreadDemo("子线程被创建");try{//子线程就绪demo.start();//子线程加入主线程demo.join();}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}//显示当前线程名System.out.println(Thread.currentThread().getName()+":"+i);}}}10.4.2后台线程1.后台线程会随着主线程的结束而结束,但是前台线程不会。或者说,只要一个前台进程未退出,进程就不会终止。2.默认情况下,程序员创建的线程是用户线程。用setDaemon(true)可以设置线程为后台线程。而用isDaemon()可以判断一个线程是前台线程还是后台线程。3. JVM的垃圾回收器其实就是一个后台线程。4. setDaemon()方法必须在start方法之前设定,否则会抛出IllegalThreadStateExcetion异常。后台线程的特点10.4.3线程睡眠1. staticvoidsleep(longmillis):让当前正在执行的线程暂停millis(毫秒),并且进入阻塞状态。该方法受到系统计时器和线程调度器的精度和准确度的影响。2.staticvoidsleep(longmillis,intnanos):让当前正在执行的线程暂停millis(毫秒)加nanos(微秒),并进入阻塞状态。这种过于精确的控制方法一般很少使用。当线程调用sleep()方法进入阻塞状态后,在其休眠时间段内,该线程不会获得执行的机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行。因此,sleep方法常用来暂停线程的执行。sleep()两种重载形式10.4.4线程让步Thread.yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当地轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。10.4.5线程优先级线程存在优先级,优先级范围为1~10。JVM线程调度程序是基于优先级的抢先调度机制。在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。当线程池中的线程都具有相同的优先级时,调度程序的JVM实现自由选择它喜欢的线程。这时候调度程序的操作有两种可能:一种是选择一个线程运行,直到它阻塞或者运行完成为止;另一种是时间分片,为线程池内的每个线程提供均等的运行机会。线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(intnewPriority)更改线程的优先级。例如:MyThreadt=newMyThread();t.setPriority(8);t.start();10.4.5线程优先级

线程优先级为1~10的正整数。JVM从不会改变一个线程的优先级。然而,1~10的值是没有保证的。一些JVM可能不识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个优先级,则两个或多个优先级的线程可能被映射为一个优先级。线程的默认优先级是5。Thread类中有三个常量定义线程优先级范围:1.staticintMAX_PRIORITY:线程可以具有的最高优先级。2.staticintMIN_PRIORITY:线程可以具有的最低优先级。 staticintNORM_PRIORITY:线程的默认优先级。线程同步10.510.5.1线程安全机制

多线程可以共享资源(文件、数据库、内存等)。当线程以并发模式访问共享数据时,共享数据可能会发生冲突。Java引入了线程同步的概念,以实现共享数据的一致性。线程同步机制能使多个线程有序地访问共享资源,而不是同时操作共享资源。

在线程异步模式的情况下,如果同一时刻有一个线程A在修改共享数据,另一个线程B在读取共享数据,当线程A没有处理完毕时,线程B肯定会得到错误的结果。如果采用多线程的同步控制机制,线程B会等待线程A修改完成后再进行数据读取。

锁机制的实现方式是在共享代码之前加入synchronized关键字。synchronized关键字可以修饰方法,也可以修饰变量。10.5.1线程安全机制

同步方法的语法格式如下。

class类名{publicsynchronized类型名称方法名称({....}}对于同步块,synchronized获取的是参数中的对象锁,格式如下。

synchronized(obj){......}

当线程执行到同步块时,必须获取obj对象的锁才能执行同步块;否则线程只能等待获得锁。值得注意的是,obj对象的作用范围不同,控制情况也不尽相同。伪代码示例如下。publicvoidmethod(){Objectobj=new0bject();//创建局部object类型对象objsynchronized(obj){//同步块//....}}10.5.2线程并发演示

一对夫妻拿着相同的银行卡号去银行取钱,一人拿着存折,另一人拿着银行卡。假如卡里有2000元钱,丈夫取了1500元,妻子在同一时间也取了1500元。如果取钱这段程序没有进行同步,也就是说这两个操作可以同时进行,当第一程序执行时,还没有把钱从卡里扣掉,妻子也可以从卡里取出1500元,即两个人从一张卡里取出3000元,这就涉及线程安全问题。如果这段代码进行同步,当存折和卡对应的同一账户被操作时,其余的线程再想去操作,只能等待,等前一个线程执行完毕,把钱从卡里扣除后,第二个线程再去操作,发现余额不足,钱就无法取出。例10-310.5.2线程并发演示

publicclassThreadTest{publicdoublemoney=2000;publicstaticvoidmain(String[]args){ThreadTestt=newThreadTest();t.qukuan();}

publicvoidqukuan(){MyThreadt1=newMyThread("丈夫",1500);MyThreadt2=newMyThread("妻子",1500);t1.start();t

温馨提示

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

最新文档

评论

0/150

提交评论