Java 实用程序设计(西电版)第10章 Java线程.ppt_第1页
Java 实用程序设计(西电版)第10章 Java线程.ppt_第2页
Java 实用程序设计(西电版)第10章 Java线程.ppt_第3页
Java 实用程序设计(西电版)第10章 Java线程.ppt_第4页
Java 实用程序设计(西电版)第10章 Java线程.ppt_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

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

文档简介

,第10章Java线程,10.1并发的基本思想10.2Java的基本线程机制10.3资源共享与同步10.4线程状态与生命周期10.5多线程与I/O:管道流,10.1并发的基本思想在深入多线程程序设计之前,读者需要了解并发的基本思想和动机。并发的第一个动机在一些操作系统原理书籍中经常被提及,即并发能够为单处理器上的程序提供性能的提升。表面上看,单处理器上运行并发程序引入了上下文切换的开销,似乎应比同样功能的顺序程序执行得慢。但在实际系统中存在阻塞的情况。也就是说,程序中的某个任务可能会被程序控制范围外的某些条件(如输入/输出)阻塞而不能继续执行。,10.2Java的基本线程机制一个线程是在进程中的一个单一的顺序执行流。每一个线程都能够驱动一个独立的子任务。CPU会为每个任务分配其占用CPU的时间,程序不需要知道CPU的数量及它所占用的CPU时间。Java的线程模型可以看做是CPU、代码和数据的封装体。线程模型的CPU可以看做是线程在占用CPU时CPU的状态;代码即CPU所执行的代码,可以由多个线程共享;数据包括线程独有数据(程序计数器、栈)和共享数据(如堆上的对象)。,1.创建线程线程的创建通常可以通过两种方式完成:实现Runnable接口和继承Thread类。Runnable接口是java.lang包中定义的一个接口,该接口包含唯一的抽象方法run()。Thread类则是创建线程的基础类。Thread类的构造方法可以传入三类参数:ThreadGroup类型的参数指明新线程所处的线程组;String类型的参数指明新线程的名称;Runnable接口类型的参数所指向的对象类型决定了线程的具体行为。,当通过实现Runnable接口来创建线程时,要完成以下工作:(1)定义一个类,该类实现Runnable接口,即在该类中提供run()方法的具体实现;(2)将该类的一个实例对象(可称为任务)传递给Thread类的构造方法构造线程对象。,当通过继承Thread类的方法创建线程时,应通过以下两步:(1)从Thread类派生出子类,并通过重写子类的run()方法提供线程体;(2)通过创建子类的对象创建线程。,2.ExecutorExecutor是J2SE5.0中引入的执行器接口,它存在于java.util.concurrent包中。Executor可以帮助用户管理线程对象,从而简化编程开发。Executor将主线程与所有任务线程分隔开,能够帮助主线程管理异步任务的执行,主线程不再需要显式地管理任务线程的生命周期。与传统的线程创建方法相比,Executor是一种更优的方式。,3.线程优先级线程的优先级将该线程的重要性传递给调度器。虽然CPU处理现有线程集合的顺序是不确定的,但调度器会倾向于让优先级较高的线程先执行。这并不代表优先级较低的线程将得不到执行,但是优先级较低的线程的执行频率会比较低。,4.睡眠sleep()与让步yield()在例10-1和例10-2中,我们都使用到了Thread类的静态方法sleep(),该方法能够将线程的执行暂停一段固定的时间,将CPU让给比当前线程优先级更低的线程。对sleep()的调用可能抛出InterruptedException异常,因为异常不能跨线程传播,因此必须在run()方法中加以捕获。,5.加入一个线程join()一个线程可以在另一个线程上调用join()方法。如果当前线程在另一个线程t上调用t.join(),那么当前线程将会被挂起,直到目标线程t结束(即t.isAlive()返回值为false)时才恢复运行。也可向join()加入一个超时参数,如果目标线程t在这段时间内还没有结束,join()总是可以返回。,例10-5TestJoin.java:线程join()示例。,6.终止线程早期的Java版本提供stop()方法强行终止一个线程,该方法在终止线程时不释放线程获得的锁,因而容易导致线程不一致,故在现代Java中已经被废止。较为安全的方式是使用一个标志,并提供方法对标志进行操作,标志的值决定了是否终止某个任务。,10.3资源共享与同步多线程机制允许我们在同一时刻做多件事情,假设这些事情之间没有干涉,那么也不会有什么问题。但很多情况下,多个线程会共享一些资源或数据,当多个线程同时操作这一资源或数据时,线程运行顺序的不确定性会导致共享资源或数据的结果产生不确定性,共享数据的一致性可能被破坏。因此,在多线程机制中,必须考虑对线程进行同步,以防止此类不一致的情况发生。,1.资源访问冲突在例10-6的AddAccount类中,我们定义了一个由多个线程共享操作的静态Account类型的成员变量account,在main()方法中,通过并发执行100个Task任务对account进行操作,每个任务的操作都会试图通过调用deposit()方法将account中具体的balance值加1。如果这100个线程依次执行,那么最终的balance值将是100。但实际上每次运行得到的balance值都不相同(72,74,99,68,),这实际上是由线程的具体步骤的执行顺序不确定导致的。,2.synchronized关键字与临界区为了解决线程不同步所导致的问题,大多数并发模式都采用序列化访问共享资源的方案,即在给定时刻仅允许一个任务访问共享资源。在访问共享资源的代码前面加上一条锁语句,使得在每一特定时刻最多只有一个任务可以访问共享资源。,从本质上讲,对方法进行synchronized标记与对一般代码片段的标记是一致的,总可以将publicsynchronizedvoidmtd()/*方法体*/转化为publicvoidmtd()synchronized(this)/*方法体*/,3.死锁的控制如果多个线程需要在多个共享对象上获得锁,那么就有可能导致死锁。假定存在两个共享对象r1和r2,t1已经获得r1的锁且正在申请r2的锁,同时,t2已经获得r2的锁且正在申请r1的锁,这时,程序状态类似于表10-3所示的两个线程均执行到第2行。由于每个线程都在等待另一个线程释放其所占有的对象锁,而同时又不会主动释放自己占有的对象锁,因此这两个线程均无法继续执行,形成死锁的状态。,4.线程的协作前文已经介绍了如何使用synchronized关键字让多个线程同步以避免竞争状态的发生,但有些时候,多个线程之间不仅需要同步使用共享数据,还需要进行某种协作共同完成一个功能。一种典型的协作方式是使用共享资源的wait()和notify()方法:对于共享资源R,线程调用R.wait()方法能够释放自己对R的锁占用,并将自己置于R的等待队列中,等待外部线程调用R.notify()或R.notifyAll()方法通知自己可以申请R的锁;当线程调用R.notify()方法或R.notifyAll()方法时,当前位于R的等待队列中的某个(或所有)线程会被置为可运行状态,并开始申请R的锁。,10.4线程状态与生命周期一个线程可以处于5种状态,如图10-1所示,其状态含义及状态转换过程简述如下。,图10-1线程的状态与生命周期,10.5多线程与I/O:管道流管道流作为一种流式I/O方式,主要用于实现线程之间数据的直接传输。与其他I/O流类似地,管道流也分为管道输入流PipedReader/PipedInputStream和管道输出流PipedWriter/PipedOutputStream。,管道流的创建是将管道输入流与管道输出流相连接,例如:PipedInputStreampin=newPipedInputStream();PipedOutputStreampout=newPipedOutputStream(pin);或PipedInputStreampin=newPipedInputStream();PipedOutputStreampout=newPipedOutputStream();pin.connect(pout);/或pout.connect(pin);,在例10-11中,创建两个

温馨提示

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

评论

0/150

提交评论