Java程序设计基础教程第10章-并发编程.ppt
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《Java程序设计基础教程第10章-并发编程.ppt》由用户(三亚风情)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 程序设计 基础教程 10 并发 编程
- 资源描述:
-
1、u刘刚刘刚 刘伟刘伟 编著编著 支持多线程是现代操作系统的一大特点,多线程的支持多线程是现代操作系统的一大特点,多线程的操作系统因为可以真正意义上地实现多任务同时运行,操作系统因为可以真正意义上地实现多任务同时运行,极大地提升了操作系统的处理速度极大地提升了操作系统的处理速度。跨平台的特性导致跨平台的特性导致JavaJava无法像无法像C C/C+/C+这些语言一样通过调用系统这些语言一样通过调用系统APIAPI来实现来实现多线程程序,所以它在语言本身加了对多线程的支持。多线程程序,所以它在语言本身加了对多线程的支持。这些功能都以面向对象的方式来实现,更加易于理解和这些功能都以面向对象的方式来
2、实现,更加易于理解和使用使用。10.1 10.1 线程与进程线程与进程 在操作系统中,通常将进程看作是系统资源分配和在操作系统中,通常将进程看作是系统资源分配和运行的基本单位,一个任务就是一个进程运行的基本单位,一个任务就是一个进程。进程拥有独。进程拥有独立的系统资源,包含立的系统资源,包含CPUCPU、内存和输入输出端口等,例、内存和输入输出端口等,例如打开的浏览器和如打开的浏览器和WordWord文档,这些相对独立的资源表明文档,这些相对独立的资源表明了进程具有动态性、并发性、独立性和异步性等特点。了进程具有动态性、并发性、独立性和异步性等特点。线程(线程(threadthread)是)是
3、“进程进程”中某个单一顺序的控制中某个单一顺序的控制流,被称为轻量级进程(流,被称为轻量级进程(lightweightlightweight processesprocesses),),是比进程更小的执行单位,也是程序执行流中最小的单是比进程更小的执行单位,也是程序执行流中最小的单位位。一个标准的线程由线程。一个标准的线程由线程IDID、当前指令指针(、当前指令指针(PCPC)、)、寄存器集合和堆栈组成。线程是进程中的一个实体,是寄存器集合和堆栈组成。线程是进程中的一个实体,是被系统独立调度和分配的基本单位,线程在运行中的资被系统独立调度和分配的基本单位,线程在运行中的资源归属于进程,同属于一
4、个进程的所有线程共享该进程源归属于进程,同属于一个进程的所有线程共享该进程所拥有的系统资源。所拥有的系统资源。一个线程可以创建和撤销另一个线程,同一个进程一个线程可以创建和撤销另一个线程,同一个进程中的多个线程也可以并发执行中的多个线程也可以并发执行。由于进程所有资源是固由于进程所有资源是固定的且线程间存在相互制约,使得线程可能处于就绪、定的且线程间存在相互制约,使得线程可能处于就绪、阻塞和运行等状态,令线程的执行呈现出间断性阻塞和运行等状态,令线程的执行呈现出间断性。线程线程之间可以共享代码和数据、实时通信、进行必要的同步之间可以共享代码和数据、实时通信、进行必要的同步操作等操作等。一个程序
5、都至少拥有一个进程;每个进程拥有一个程序都至少拥有一个进程;每个进程拥有一个或者多个线程一个或者多个线程。每个线程都有自己独立的资源和生每个线程都有自己独立的资源和生命周期命周期。进程和线程的最大区别在于,进程是由操作系统来进程和线程的最大区别在于,进程是由操作系统来控制的,而线程则是由进程来控制的控制的,而线程则是由进程来控制的。进程都是相互独。进程都是相互独立的,各自享有各自的内存空间,因此进程间的通信是立的,各自享有各自的内存空间,因此进程间的通信是昂贵且受限的,进程间的转换也是需要开销的;线程则昂贵且受限的,进程间的转换也是需要开销的;线程则共享进程的内存空间,线程通信是便宜的且线程间
6、的转共享进程的内存空间,线程通信是便宜的且线程间的转换也是低成本的,这种低成本低开销的通信也可能会产换也是低成本的,这种低成本低开销的通信也可能会产生意想不到的错误:当多个线程访问同一个变量时,获生意想不到的错误:当多个线程访问同一个变量时,获取到的值是不一样的!取到的值是不一样的!不过,也不必担心,这些问题可不过,也不必担心,这些问题可以通过同步机制和锁机制来消除以通过同步机制和锁机制来消除。10.2 10.2 线程的创建线程的创建 多线程技术是多线程技术是JavaJava语言的重要特性之一,语言的重要特性之一,JavaJava平台平台提供了一套广泛且功能强大的提供了一套广泛且功能强大的AP
7、IAPI、工具和技术、工具和技术。JavaJava编写的程序都运行在编写的程序都运行在JavaJava虚拟机(虚拟机(JVMJVM)中)中。在。在JVMJVM内部,内部,程序的多任务是通过线程来实现的。在同一个程序的多任务是通过线程来实现的。在同一个JVMJVM进程进程中,有且只有一个进程,那就是中,有且只有一个进程,那就是JVMJVM本身,在本身,在JVMJVM环境中,环境中,所有的程序代码都是以线程来运行的。所有的程序代码都是以线程来运行的。JavaJava中的线程有两种实现方式,中的线程有两种实现方式,一种是继承一种是继承ThreadThread类,一种是实现类,一种是实现Runnabl
8、eRunnable接口接口。但是无论是哪种方式,但是无论是哪种方式,线程都要使用到线程都要使用到ThreadThread类及其相关方类及其相关方法法。10.2.1 10.2.1 继承继承ThreadThread类类 Thread Thread类是一个实体类,该类封装了线程的行为,类是一个实体类,该类封装了线程的行为,想要利用想要利用ThreadThread创建一个线程,必须创建一个从创建一个线程,必须创建一个从ThreadThread类导出的子类,并实现类导出的子类,并实现ThreadThread的的run()run()方法,在方法,在runrun()()方法内部可以根据需要编写相应的实现逻辑
9、,最后调用方法内部可以根据需要编写相应的实现逻辑,最后调用ThreadThread类的类的startstart()()方法来启动方法来启动。Thread Thread的构造方法有很多种,每种构造方法用途各的构造方法有很多种,每种构造方法用途各异,如表异,如表10-110-1所示。所示。构造方法构造方法说明说明Thread()构造一个线程对象构造一个线程对象Thread(Runnable target)构造一个线程对象,构造一个线程对象,target是被创建线程是被创建线程的目标对象,它实现了的目标对象,它实现了Runnable接口中的接口中的run()方法方法Thread(String nam
10、e)以指定名称构造一个线程对象以指定名称构造一个线程对象Thread(ThreadGroup group,Runnable target)在指定线程组中构造一个线程对象,使用在指定线程组中构造一个线程对象,使用目标对象的目标对象的target的的run()方法方法Thread(Runnable target,String name)以指定名称构造一个线程对象,使用目标以指定名称构造一个线程对象,使用目标对象对象target的的run()方法方法Thread(ThreadGroup group,Runnable target,String name)在指定的线程组中创建一个指定名称的线在指定的线
11、程组中创建一个指定名称的线程,使用目标对象程,使用目标对象target的的run()方法方法Thread(ThreadGroup group,Runnable target,String name,long stackSize)在指定线程组中构造一个线程对象,以在指定线程组中构造一个线程对象,以name作为线程的名字,使用目标对象作为线程的名字,使用目标对象target的的run()方法,方法,stackSize指定堆栈大小指定堆栈大小表表10-1 Thread类的构造方法类的构造方法 Thread Thread也提供了很多辅助方法,以让线程正常运行也提供了很多辅助方法,以让线程正常运行和方便
12、程序员对线程的控制,其常用方法如表和方便程序员对线程的控制,其常用方法如表10-210-2所示。所示。方法名方法名说明说明static int activeCount()返回线程组中正在运行的线程的数目返回线程组中正在运行的线程的数目void checkAccess()确定当前运行的线程是否有权限修改线程确定当前运行的线程是否有权限修改线程static Thread currentThread()返回当前正在执行的线程返回当前正在执行的线程void destroy()销毁线程,但不回收资源销毁线程,但不回收资源static void dumpStack()显示当前线程的堆栈信息显示当前线程的堆
13、栈信息long getId()返回当前线程的返回当前线程的id值值String getName()返回当前线程的名称返回当前线程的名称int getPriority()返回当前线程的优先级返回当前线程的优先级Thread.State getState()返回当前线程的状态返回当前线程的状态ThreadGroup getThreadGroup()返回当前线程所属的线程组返回当前线程所属的线程组void interrupt()中断线程中断线程boolean isAlive()判断当前线程是否存活判断当前线程是否存活boolean isDaemon()判断当前线程是否是守护线程判断当前线程是否是守护
14、线程boolean isInterrupted()判断本线程是否被中断判断本线程是否被中断void join()等待直到线程死亡等待直到线程死亡void join(long millis)等待最多等待最多millis毫秒,直到线程死亡毫秒,直到线程死亡void run()如果类是使用单独的如果类是使用单独的Runnable对象构造的,将调用对象构造的,将调用Runnable对对象的象的run()方法,否则本方法不做任何事情就返回了,如果是子类方法,否则本方法不做任何事情就返回了,如果是子类继承继承Thread类,请务必实现本方法以覆盖父类类,请务必实现本方法以覆盖父类void setDaemo
15、n(boolean on)将当前线程设置为守护线程将当前线程设置为守护线程void setName(String name)将当前线程名称修改为将当前线程名称修改为namevoid setPriority(int newPriority)设置当前线程的优先级设置当前线程的优先级static void sleep(long millis)线程休眠线程休眠millis毫秒毫秒void start()启动线程,启动线程,JVM会自动调用会自动调用run()方法方法static void yield()暂停当前线程,同时允许其他线程运行暂停当前线程,同时允许其他线程运行表表10-2 常用的常用的Thr
16、ead方法方法 在以前的案例中,当需要执行当前类时,每个类都在以前的案例中,当需要执行当前类时,每个类都有一个有一个mainmain()()方法方法。该方法是类的入口,。该方法是类的入口,JVMJVM会找到该入会找到该入口方法并运行,此时产生了一个线程,该线程便是主线程。口方法并运行,此时产生了一个线程,该线程便是主线程。当当mainmain()()方法运行结束后,主线程运行完成,方法运行结束后,主线程运行完成,JVMJVM也就随也就随即退出了。即退出了。JVMJVM负责对进程、线程进行管理,负责对进程、线程进行管理,JVMJVM分配时分配时间片(间片(CPUCPU时间)给线程,线程按照系统的
17、设定轮流获取时间)给线程,线程按照系统的设定轮流获取时间片执行,切换时间很短,在对线程运行效率要求不严时间片执行,切换时间很短,在对线程运行效率要求不严格的场景下可以忽略不计。格的场景下可以忽略不计。运行结果如图运行结果如图10-110-1所示。所示。图图10-1 运行结果运行结果 由于每个线程运行的次数较少,所以线程默认优先由于每个线程运行的次数较少,所以线程默认优先级下的运行随机性不是很明显,但通过方框标注的线程级下的运行随机性不是很明显,但通过方框标注的线程Thread-3Thread-3的运行可以看出,实际上线程运行并不是顺序的运行可以看出,实际上线程运行并不是顺序的。的。运行结果如图
18、运行结果如图10-210-2所示。所示。图图10-2 运行结果运行结果 运行结果如图运行结果如图10-310-3所示。所示。图图10-3 运行结果运行结果 启动启动ThreadThread类时,必须要使用类时,必须要使用startstart()()方法启动一方法启动一个线程,如果直接调用个线程,如果直接调用runrun()()方法,则方法,则JVMJVM认为这只是一认为这只是一次普通的方法调用,而非需要启动一个线程在执行次普通的方法调用,而非需要启动一个线程在执行runrun()()方法内部的逻辑方法内部的逻辑。读者在使用线程的时候切记读者在使用线程的时候切记。在在startstart()()
19、方法调用后也可以看出,运行的是两个线程的方法调用后也可以看出,运行的是两个线程的代码,而且它们之间互不干扰地同时执行代码,而且它们之间互不干扰地同时执行。所以一些工所以一些工作交给线程去做的时候,启动一个新线程的线程可以做作交给线程去做的时候,启动一个新线程的线程可以做自己想做的其他事情,而无需等到新线程的执行结束自己想做的其他事情,而无需等到新线程的执行结束。10.2.2 10.2.2 实现实现RunnableRunnable接口接口 实现多线程的另一个方式是实现实现多线程的另一个方式是实现RunnableRunnable接口接口。RunnableRunnable只有一个方法,即只有一个方法
20、,即runrun()()方法,该方法需方法,该方法需要由一个实现了此接口的类来实现要由一个实现了此接口的类来实现。实现了实现了RunnableRunnable接接口的类的对象需要由口的类的对象需要由ThreadThread类的一个实例内部运行它,类的一个实例内部运行它,其本身不能直接运行其本身不能直接运行。运行结果如图运行结果如图10-410-4所示。所示。图图10-4 运行结果运行结果 图图10-410-4只摘取部分的输出内容,从内容上看,实现只摘取部分的输出内容,从内容上看,实现RunnableRunnable和继承和继承ThreadThread都能达到相同目的,都能启动一都能达到相同目的
21、,都能启动一个新线程。个新线程。唯一的区别是唯一的区别是RunnableRunnable对象必须包装成对象必须包装成ThreadThread对象后才能运行对象后才能运行。如果查看如果查看ThreadThread和和RunnableRunnable类源码会发现,类源码会发现,ThreadThread类实际上是类实际上是RunnableRunnable的一个实现的一个实现类类。可能有读者会对可能有读者会对RunnableRunnable接口的存在产生疑问,毕接口的存在产生疑问,毕竟这个接口只有一个竟这个接口只有一个runrun()()方法方法。RunnableRunnable的存在是因的存在是因为
22、为JavaJava的类有且只能有一个直接父类,如果只是提供了的类有且只能有一个直接父类,如果只是提供了ThreadThread类,那么想要继承其他类且需要同时继承类,那么想要继承其他类且需要同时继承ThreadThread类的这个子类,在实现这种继承逻辑上会产生很多困难,类的这个子类,在实现这种继承逻辑上会产生很多困难,而而RunnableRunnable则避免了这种尴尬局面的出现,在则避免了这种尴尬局面的出现,在JavaJava中,中,一个类是可以实现多个接口的。一个类是可以实现多个接口的。10.3 10.3 线程的调度线程的调度 在在JVMJVM中,线程只有在获取了中,线程只有在获取了CP
23、UCPU分配的时间片后才分配的时间片后才会真正地执行,在线程创建后到死亡的这个过程中还有会真正地执行,在线程创建后到死亡的这个过程中还有其他的线程状态,这些状态组成了线程的生命周期。其他的线程状态,这些状态组成了线程的生命周期。10.3.1 10.3.1 线程的生命周期线程的生命周期 如同生命体一般,线程也有生命周期,线程的生命如同生命体一般,线程也有生命周期,线程的生命周期是从线程新建开始,一直持续到线程死亡周期是从线程新建开始,一直持续到线程死亡。在新建。在新建和死亡之间,线程还有就绪、阻塞和运行状态,一个线和死亡之间,线程还有就绪、阻塞和运行状态,一个线程会在这程会在这5 5种状态间转换
24、,最终完成自己的使命。种状态间转换,最终完成自己的使命。线程的状态及转换关系如图线程的状态及转换关系如图10-510-5所示。所示。图图10-5 Java线程状态转换图线程状态转换图 线程各个状态的说明如下线程各个状态的说明如下。新建:当创建一个新建:当创建一个ThreadThread类和它的子类、对象后,线程就类和它的子类、对象后,线程就处于新建状态,这种状态的线程并不具备运行的能力,该操处于新建状态,这种状态的线程并不具备运行的能力,该操作对于系统而言,仅仅消耗普通对象创建时会消耗的非作对于系统而言,仅仅消耗普通对象创建时会消耗的非CPUCPU资资源。源。就绪:当处于新建状态的线程调用就绪
25、:当处于新建状态的线程调用startstart()()方法被启动之方法被启动之后,线程将进入线程队列等待后,线程将进入线程队列等待CPUCPU时间片,进行执行。时间片,进行执行。此时的此时的线程才具备了运行的能力,一旦获取了时间片线程就执行线程才具备了运行的能力,一旦获取了时间片线程就执行。运行:就绪状态的线程获取了时间片之后,就进入了运行运行:就绪状态的线程获取了时间片之后,就进入了运行状态,此时线程会执行状态,此时线程会执行runrun()()方法内的代码逻辑方法内的代码逻辑。线程一旦进线程一旦进入运行状态,就与启动该线程的线程没有任何关系了,两者入运行状态,就与启动该线程的线程没有任何关
展开阅读全文