Java程序设计 教学课件 ppt 作者 刘慧宁 14 14

上传人:E**** 文档编号:89156062 上传时间:2019-05-19 格式:PPT 页数:76 大小:504.51KB
返回 下载 相关 举报
Java程序设计 教学课件 ppt 作者 刘慧宁 14 14_第1页
第1页 / 共76页
Java程序设计 教学课件 ppt 作者 刘慧宁 14 14_第2页
第2页 / 共76页
Java程序设计 教学课件 ppt 作者 刘慧宁 14 14_第3页
第3页 / 共76页
Java程序设计 教学课件 ppt 作者 刘慧宁 14 14_第4页
第4页 / 共76页
Java程序设计 教学课件 ppt 作者 刘慧宁 14 14_第5页
第5页 / 共76页
点击查看更多>>
资源描述

《Java程序设计 教学课件 ppt 作者 刘慧宁 14 14》由会员分享,可在线阅读,更多相关《Java程序设计 教学课件 ppt 作者 刘慧宁 14 14(76页珍藏版)》请在金锄头文库上搜索。

1、第14章 多线程,14.1 线程简介 14.2 创建任务和线程 14.3 线程属性 14.4 线程池 14.5 异常与线程,第14章 多线程(续),14.6 共享资源 14.7 线程的状态 14.8 线程安全的类 14.9 Swing与线程 14.10 习题,14.1 线程简介,使用多线程可以将一个程序划分为多个独立的子任务,每个子任务都能同时运行。 程序的一次执行过程称为一个进程。进程是一个“自包含”的运行程序,有自己专用的内存地址。 线程是指一个程序中可以独立运行的片断,是进程中的一个单一而连续的控制流程。 一个进程可以包含多个线程,每个线程独立运行以执行特定的任务,而且同一进程内的多个线

2、程间共享内存等资源。,14.1 线程简介(续),对于单CPU平台,多任务操作系统能使多个进程循环获得自己的CPU时间片,由于循环的速度非常快,可以把它想象成每个进程都有自己专用的CPU,即多个程序(进程)在同时运行;对于多CPU平台,多任务操作系统能确保多个进程同时获得自己的CPU时间片。 多线程在较低的层次上扩展了多任务的概念,它使得一个程序中可以有多个线程同时运行。 可以同时运行一个以上线程的程序称为多线程程序。,14.1 线程简介(续),主线程由系统自动创建并启动。当程序作为application运行时,主线程就是方法main的执行路径;当程序作为applet运行时,主线程就是apple

3、t装载运行的路径。,14.2 创建任务和线程,要实现多线程,就必须在主线程或其他已经存在的线程中创建新的线程对象。 为了创建新线程,应该首先定义该线程将执行的特定子任务。一般来说,为了定义线程的子任务,就需要定义一个实现接口java.lang.Runnable的任务类。 接口Runnable中只有一个无参数方法run,实现该接口时,在方法run中定义相应线程的子任务代码。,14.2 创建任务和线程(续),定义某个任务类后,如果需要创建一个执行相应子任务的新线程,只需首先创建一个该类的对象,然后以该对象为参数,使用类java.lang.Thread创建一个Thread对象,即线程对象。最后,调用

4、类Thread中定义的方法start启动当前线程来执行相应子任务。 例14-1 一个简单的多线程程序,源代码,运 行,14.2 创建任务和线程(续),方法start运行时,首先会为当前线程进行特殊的初始化,然后使当前线程开始运行(系统会在这个当前线程中自动调用该线程的方法run)。一旦当前线程开始运行,方法start就立即返回,而当前线程会继续运行。,14.2 创建任务和线程(续),程序中不要直接调用Runnable对象的方法run。直接调用该方法,与调用其他普通方法的效果一样,只会在同一线程中执行其中的代码,不会启动新线程。 不调用方法start,新线程永远不会开始运行。此外,也不能针对同一

5、个线程,多次调用方法start。多次调用方法start启动同一个线程是非法的。,14.2 创建任务和线程(续),类Thread实现了接口Runnable,因此,也可以通过定义一个类Thread的子类来定义线程的子任务。 除非程序员打算修改或增强某个类的基本行为,否则不应该为该类创建子类。类Thread中定义有许多控制线程的方法,而为了定义线程子任务只需覆盖其中的方法run,因此,现在这种方法已不再推荐使用。,14.3 线程属性,14.3.1 线程优先级 14.3.2 守护线程,14.3.1 线程优先级,每个线程都有一个优先级。 当某个线程中运行的代码创建一个新线程对象时,该新线程的初始优先级被

6、设定为创建线程的优先级。程序中,可以调用类Thread中定义的方法setPriority更改当前线程的优先级;调用类Thread中定义的方法getPriority返回当前线程的优先级。,14.3.1 线程优先级(续),线程的优先级标示了该线程的重要性,线程调度器(Java线程机制之一,可以将CPU从一个线程转移给另一个线程)倾向于让高优先级的线程先执行。不过,这并不意味着优先级较低的线程将得不到执行,优先级较低的线程仅仅是执行的频率较低。,14.3.1 线程优先级(续),线程有10个优先级别。它们分别用最低优先级常量Thread.MIN_PRIORITY和最高优先级常量Thread.MAX_P

7、RIORITY之间的10个int型值表示。其中,常量Thread.MIN_PRIORITY的值是10;常量Thread.MAX_PRIORITY的值是1。此外,类Thread中还定义有默认优先级常量NORM_PRIORITY,该常量的值是5,主线程的默认优先级就是Thread.NORM_PRIORITY。,14.3.1 线程优先级(续),线程的实际优先级是高度依赖于系统的。Java线程的优先级通常会被映射到其运行平台操作系统的优先级上。由于每种操作系统中的优先级别都可能不同,或者更多,或者更少(比如,Windows操作系统只有7个优先级别),因此,这种映射关系是不确定的。所以,一般来说,所有线

8、程都应该以默认优先级运行,不能将程序的功能正确性设计为依赖于线程的优先级,试图更改线程的优先级通常是一种错误。,14.3.2 守护线程,线程可分为用户线程和守护线程。 程序运行时,系统首先创建并启动一个主线程。主线程是用户线程,在用户线程中创建的线程默认情况下是用户线程,可以调用类Thread中定义的方法setDaemon将当前线程转换为守护线程。这个方法必须在当前线程启动前调用(因此,主线程不能转换为守护线程),否则,程序运行时将抛出异常。当传递给该方法的参数是true时,当前线程就转换为守护线程。,14.3.2 守护线程(续),守护线程中创建的线程默认情况下是守护线程,同样,可以调用类Th

9、read中定义的方法setDaemon将当前线程转换为用户线程(方法参数应为false)。 守护线程也称后台线程,这种线程与用户线程的区别在于当一个程序中的所有用户线程都结束运行时,程序会立即结束运行,不管当时是否还有守护线程正在运行,但是只要该程序中还有正在运行的用户线程,该程序就不会结束运行。,14.3.2 守护线程(续),守护线程通常用来在后台为其他线程提供服务,它不属于程序中必需的部分。 例14-2 守护线程的运行,源代码,运 行,14.4 线程池,Java SE5之后,程序中如果需要执行多个子任务,就应该优先选用线程池。 为了创建一个线程池对象(也称作线程池执行器对象,即Execut

10、orService对象,更准确地说是ThreadPoolExecutor对象),需要使用类java.util.concurrent.Executors。,14.4 线程池(续),类Executors中的静态方法newCachedThreadPool用于创建一个可根据需要创建新线程的线程池(执行新任务时,如果线程池中以前创建的某个线程可用则重用它,不创建新线程);静态方法newFixedThreadPool用于创建一个可重用的包含指定数量线程的线程池(因此,可以限制程序中并发线程的数量,阻止因创建大量线程而大大降低程序性能)。,14.4 线程池(续),接口ExecutorService是java

11、.util.concurrent.Executor的子接口,其中,接口Executor定义有方法execute用于执行Runnable参数指定的任务;接口ExecutorService定义有方法用于管理当前线程池,比如,调用其中的方法shutdown,就可以关闭当前线程池,这将导致该线程池不接受新任务,不过,以前提交的任务会继续执行,当其中的所有任务都执行完毕后,该线程池中的所有线程都将终止并被系统销毁。,14.4 线程池(续),类ThreadPoolExecutor实现了这两个接口,其中,方法execute被实现用于在当前线程池的某个线程中执行Runnable参数指定的任务。 例14-3 线

12、程池的使用,源代码,运 行,14.4 线程池(续),如果将例14-3中创建线程池的语句改为如下形式: ExecutorService exec = Executors.newCachedThreadPool(); 可以发现,所有任务都并发执行。这是因为方法Executors.newCachedThreadPool创建的线程池中如果没有可用的空闲线程,而且有任务在等待执行,该线程池就会创建新线程去执行正在等待的任务。不过,这种线程池中的某个线程如果在60秒内都没有使用,系统会自动终止并从缓存中移除它。所以,这种线程池长时间保持空闲不会占用任何资源。因此,如果某个程序中有许多需要执行的短小任务,使

13、用这种线程池执行通常可以提高性能。,14.4 线程池(续),调用方法Executors.newFixedThreadPool创建的线性池在被显式关闭之前,其中的线程将一直存在。 方法Executors.newFixedThreadPool创建的线程池中,如果在关闭前的执行期间由于异常等原因而导致任何线程终止并被销毁,那么如果还有新任务在等待执行,系统会自动创建一个新线程代替它执行后续任务。,14.5 异常与线程,所有异常都不能在线程间传播(即不能从一个线程返回给另一个线程)。必检异常必须在当前线程的方法中进行捕获(应用程序的主线程除外,因为主方法可以声明必检异常)。免检异常可以在当前线程的方法

14、中进行捕获,也可以不捕获。如果不捕获,该免检异常不会返回给创建当前线程的线程,而是直接返回给运行当前线程的系统,这将导致当前线程终止运行并被系统销毁。,14.5 异常与线程(续),某个线程因未捕获的异常而突然终止时,系统一般将调用默认的异常处理方法。 也可以为线程指定特定的未捕获异常处理方法。Java SE5之后,可以使用实现了内部接口Thread.UncaughtExceptionHandler的类的对象,并调用类Thread中定义的方法setUncaughtExceptionHandler或静态方法setDefaultUncaughtExceptionHandler。,14.6 共享资源,

15、14.6.1 共享资源冲突 14.6.2 使用Lock锁实现同步 14.6.3使用关键字synchronized实现同步 14.6.4 线程间协作 14.6.5 死锁,14.6.1 共享资源冲突,多线程环境下,资源可以共享,因此可能存在多个并发线程同时访问同一资源,从而引起资源冲突的情况。 例14-4 资源冲突举例,源代码,运 行,14.6.1 共享资源冲突(续),原子操作是指在执行过程中不能被线程调度机制中断的操作。 除long和double型外,基本数据类型变量的赋值和读取操作都是原子性的,这些类型通常称为原子类型。,14.6.2 使用Lock锁实现同步,为避免多线程引起的资源冲突,需要防

16、止多个线程同时访问同一资源。 为防止多个线程同时访问某一资源,就需要防止多个线程同时执行程序中那些访问表示该资源的对象的部分。程序中这样的部分称为临界区。,14.6.2 使用Lock锁实现同步(续),为保证某个临界区中的代码在一段时间内只被一个线程执行(即线程同步),需要在第1个线程开始执行这个临界区中的代码时,给这个临界区加锁,其他线程在这个临界区被解锁前,无法执行其中的代码,而在其被解锁之后,另一个线程就可以锁定并执行其中的代码,依此类推。,14.6.2 使用Lock锁实现同步(续),Java语言为同步线程提供了两种机制:使用关键字synchronized或Java SE5引入的类java.util.concurrent.locks.ReentrantLock。 关键字synchronized隐式使用锁;而类ReentrantLock显式使用锁。,14.6.2 使用Lock锁实现同步(续),/应该是类的成员,类ReentrantLock实现了接口Lock Lock lock = new ReentrantLock(); lock.l

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号