JAVA学习-第13章线程.ppt

上传人:max****ui 文档编号:6360135 上传时间:2020-02-23 格式:PPT 页数:31 大小:314.50KB
返回 下载 相关 举报
JAVA学习-第13章线程.ppt_第1页
第1页 / 共31页
JAVA学习-第13章线程.ppt_第2页
第2页 / 共31页
JAVA学习-第13章线程.ppt_第3页
第3页 / 共31页
点击查看更多>>
资源描述
江苏大学计算机学院Version2 0 第13章线程 Page2 定义线程在Java技术程序中创建不同的线程 控制由线程使用的代码和数据控制线程的执行并编写独立于平台的线程代码描述当多个线程共享数据时可能会产生的问题使用等待和通知在线程之间进行通信使用同步来保护数据免受损害 内容 Page3 程序 进程和线程 程序是一段静态的代码 它是应用软件执行的蓝本 进程是程序的一次动态执行过程 它对应了从代码加载 执行至执行完毕的一个完整过程 这个过程也是进程本身从产生 发展至消亡的过程 线程是比进程更小的执行单位 一个进程在其执行过程中 可以产生多个线程 形成多条执行线索 每条线索 即每个线程也有它自身的产生 存在和消亡的过程 也是一个动态的概念 Java的多线程就是在操作系统每次分时给Java程序一个时间片的CPU时间内 在若干个独立的可控制的线程之间切换 每个Java程序都有一个缺省的主线程 我们已经知道 Java应用程序总是从主类的main方法开始执行 当JVM加载代码 发现main方法之后 就会启动一个线程 这个线程称作 主线程 该线程负责执行main方法 那么 在main方法的执行中再创建的线程 就称为程序中的其它线程 如果main方法中没有创建其他的线程 那么当main方法执行完最后一个语句 即main方法返回时 JVM就会结束我们的Java应用程序 如果main方法中又创建了其他线程 那么JVM就要在主线程和其他线程之间轮流切换 保证每个线程都有机会使用CPU资源 main方法即使执行完最后的语句 JVM也不会结束我们的程序 JVM一直要等到程序中的所有线程都结束之后 才结束我们的Java应用程序 Page4 线程的基本概念 线程是一个程序内部的顺序控制流 线程和进程的区别每个进程都有独立的代码和数据空间 进程上下文 进程间的切换会有较大的开销 线程可以看成时轻量级的进程 同一类线程共享代码和数据空间 每个线程有独立的运行栈和程序计数器 PC 线程切换的开销小 多进程 在操作系统中能同时运行多个任务 程序 多线程 在同一应用程序中有多个顺序流同时执行 Java的线程是通过java lang Thread类来实现的 VM启动时会有一个由主方法 publicstaticvoidmain 所定义的线程 可以通过创建Thread的实例来创建新的线程 每个线程都是通过某个特定Thread对象所对应的方法run 来完成其操作的 方法run 称为线程体 通过调用Thead类的start 方法来启动一个线程 Page5 线程 线程是虚拟的CPU和自身程序代码和数据的封装 线程的三个部分是 虚拟CPU线程体数据 线程或执行环境 Page6 线程的创建和启动 可以有两种方式创建新的线程 第一种定义线程类实现Runnable接口ThreadmyThread newThead target target为Runnable接口类型 Runnable中只有一个方法 publicvoidrun 用以定义线程运行体 使用Runnable接口可以为多个线程提供共享的数据 在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法 publicstaticThreadcurrentThread 获取当前线程的引用 第二种可以定义一个Thread的子类并重写其run方法如 classMyThreadextendsThead publicvoidrun 然后生成该类的对象 MyThreadmyThread newMyThead 使用那种好呢 TestThread1 java Page7 创建线程 续 多线程的程序设计具有以下几个特性 多个线程是来自于一个可运行的实例 线程共享相同的数据和代码 例如 Threadt1 newThread r Threadt2 newThread r Page8 启动线程 新创建的线程不会字符开始运行使用start 方法调用start 方法可将该线程包含的虚拟CPU设置为一种可运行的状态 这意味着JVM可以调度执行该线程 但不一定意味着该线程立即开始执行 Page9 线程模式 两种线程模式 协作式 一个线程保留对处理器的控制直到它自己决定放弃速度快 代价低用户编程非常麻烦抢先式 系统可以任意的从线程中夺回对CPU的控制权 再把控制权分给其它的线程 两次切换之间的时间间隔就叫做时间片效率不如协作式高 OS核心必须负责管理线程简化编程 而且使程序更加可靠多数线程的调度是抢先式的 Page10 线程调度 基本的线程状态图 Page11 线程调度示例 publicclassRunnerimplementsRunnable publicvoidrun while true 执行许多感兴趣的操作 给其他线程一个机会try Thread sleep 10 catch InterruptedExceptione 另一个线程中断了该线程的睡眠 线程调度 续 线程调度方法之一 Page12 终止线程 线程到达其run 方法的末尾 线程抛出未捕捉到的异常或错误 另一个线程调用不建议使用的某个stop 方法 Page13 线程控制基本方法 Page14 sleep join yield方法 sleep方法可以调用Thread的静态方法 publicstaticvoidsleep longmillis throwsInterruptedException使得当前线程休眠 暂时停止执行millis毫秒 由于是静态方法 sleep可以由类名直接调用 Thread sleep join方法合并某个线程yield方法让出CPU 给其他线程执行的机会 TestInterrupt java TestJoin java TestYield java Page15 线程的优先级别 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程 线程调度器按照线程的优先级决定应调度哪个线程来执行 线程的优先级用数字表示 范围从1到10 一个线程的缺省优先级是5 Thread MIN PRIORITY 1Thread MAX PRIORITY 10Thread NORM PRIORITY 5使用下述线方法获得或设置线程对象的优先级 intgetPriority voidsetPriority intnewPriority 不同平台上的优先级Solaris 相同优先级的线程不能相互抢占对方的cpu时间 windows 可以抢占相同甚至更高优先级的线程的cpu时间 例 TestThread6 java TestPriority java Page16 临界资源问题 1 两个线程A和B在同时操纵Stack类的同一个实例 堆栈 A正在往堆栈里push一个数据 B则要从堆栈中pop一个数据 classStack intidx 0 char data newchar 6 publicvoidpush charc data idx c idx publiccharpop idx returndata idx Page17 临界资源问题 2 1 操作之前data a b idx 22 A执行push中的第一个语句 将c推入堆栈 data a b c idx 23 A还未执行idx 语句 A的执行被B中断 B执行pop方法 返回c data a b c idx 14 A继续执行push的第二个语句 data a b c idx 2最后的结果相当于c没有入栈 产生这种问题的原因在于对共享数据访问的操作的不完整性 Page18 线程同步 publicclassTestimplementsRunnable Timertimer newTimer publicstaticvoidmain String args Testtest newTest Threadt1 newThread test Threadt2 newThread test t1 setName t1 t2 setName t2 t1 start t2 start publicvoidrun timer add Thread currentThread getName classTimer privatestaticintnum 0 publicvoidadd Stringname num try Thread sleep 1 catch InterruptedExceptione System out println name 你是第 num 个使用timer的线程 TestSync java Page19 线程同步 在Java语言中 引入了对象互斥锁的概念 保证共享数据操作的完整性 每个对象都对应于一个可称为 互斥锁 的标记 这个标记保证在任一时刻 只能有一个线程访问该对象 关键字synchronized来与对象的互斥锁联系 当某个对象synchronized修饰时 表明该对象在任一时刻只能由一个线程访问 synchronized this num try Thread sleep 1 catch InterruptedExceptione System out println name 你是第 num 个使用timer的线程 synchronized的使用方法 synchronized还可以放在方法声明中 表示整个方法为同步方法 例如 synchronizedpublicvoidadd Stringname Page20 同步时的线程状态图 使用同步 续 Page21 死锁 死锁有以下特性 它是两个线程 彼此都等待着对方的锁 它是没有检测到或没有避免发生的 通过以下操作可以避免发生死锁 决定要获取锁的顺序全程遵循这个顺序以相反的顺序释放锁 死锁TestDeadLock java Page22 线程交互 wait和notify方法场景 把您自己和汽车驾驶员作为两个线程 问题 您怎么确定何时能够到达目的地 解决方法 通知汽车驾驶员您的目的地驾驶员驾驶并在到达目的地时通知您 Page23 线程交互 续 线程交互包括 wait 和notify 方法Java lang Object类为线程提供的通信方法如果线程对共享数据 对象 发出wait调用 则该线程暂停 一直等待到另一线程对共享数据 对象 发出notify调用后才继续执行池有 等待池假设一个线程A调用了某个对象的wait 方法 线程A就会释放该对象的锁 因为wait 方法必须出现在synchronized中 这样自然在执行wait 方法之前线程A就已经拥有了该对象的锁 同时线程A就进入到了该对象的等待池中 如果另外的一个线程调用了相同对象的notifyAll 方法 那么处于该对象的等待池中的线程就会全部进入该对象的锁池中 准备争夺锁的拥有权 如果另外的一个线程调用了相同对象的notify 方法 那么仅仅有一个处于该对象的等待池中的线程 随机 会进入该对象的锁池 锁定池假设线程A已经拥有了某个对象 注意 不是类 的锁 而其它的线程想要调用这个对象的某个synchronized方法 或者synchronized块 由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权 但是该对象的锁目前正被线程A拥有 所以这些线程就进入了该对象的锁池中 例 ProducerConsumer java Page24 线程交互 续 使用wait 和notify 方法的线程状态图 Page25 关于wait和notify的几点说明 第一 wait 和notify 方法要配套使用 运行中的线程因为wait方法而阻塞 只有被当前执行的线程调用notify 方法才可重新加入锁申请的就绪队列 第二 这一对方法必须在syschronized设置的方法或者块中调用 即必须在互斥方法的临界区代码段中调用 因为只有在临界区中执行的当前线程才能占有锁 才有锁可以释放 同理 调用这一对方法的对象必须为当前正在运行的 拥有锁的线程对象 这样才可以有锁可以释放 否则程序虽然能编译 但是在运行的时候会出现IllegalMonitorException异常第二 当对对象调用notify 方法时 并且如果有其他线程通过wait 方法等待该对象 则会唤醒一个线程 当对对象调用notifyAll 方法时 会唤醒所有等待该对象的线程 Page26 wait和sleep方法的区别 Wait和sleep方法都是使当前正在运行的进程进入阻塞状态wait 使一个线程处于等待状态 并且释放所持有的对象的lock sleep 使一个正在运行的线程处于睡眠状态 是一个静态方法 并不释放已持有的锁 调用此方法要捕捉InterruptedException异常 Page27 同步的监控模型 将共享数据保留为一致的状态确保程序不能死锁不要期望同一个等待池中的线程有不同的通知 Page28 Synchronized总结 无论synchronized关键字加在方法上还是对象上 它取得的锁都是锁在了对象上 而不是把一段代码或函数当作锁 而且同步方法很可能还会被其他线程的对象访问 每个对象只有一个锁 lock 与之相关联 实现同步是要很大的系统开销作为代价的 甚至可能造成死锁 所以尽量避免无谓的同步控制 搞清楚synchronized锁定的是哪个对象 就能帮助我们设计更安全的多线程程序 还有一些技巧可以让我们对共享资源的同步访问更加安全 定义private的instance变量 它的get方法 而不要定义public protected的instance变量 如果将变量定义为public 对象在外界可以绕过同步方法的控制而直接取得它 并改动它 如果instance变量是一个对象 如数组或ArrayList什么的 那上述方法仍然不安全 因为当外界对象通过get方法拿到这个instance对象的引用后 又将其指向另一个对象 那么这个private变量也就变了 岂不是很危险 这个时候就需要将get方法也加上synchronized同步 并且 只返回这个private对象的clone 这样 调用端得到的就是对象副本的引用了 Page29 小结 线程是虚拟的CPU 线程的三个部分是CPU 代码和数据线程可以通过从Thread类扩展或实现可运行接口来创建 Java程序可以有多个线程 线程需要通过使用start 方法来启动 线程的各种状态有可运行 正在运行和锁定 sleep 方法暂停线程给定一段时间 run 方法完成后 线程就死亡 sleep join 和yield 方法使线程处于保持状态 使用getPriority 方法确定线程的当前优先级 Page30 小结 续 当多个线程使用共享数据时 应该使用同步的关键字来维护数据的一致性 死锁是两个线程彼此都在等待对方锁的一种情况 wait 和notify 是线程通信的方法 Page31 程序 进程 线程的区别 程序是指令的有序集合 其本身没有任何运行的含义 是一个静态的概念 而进程是程序在处理机上的一次执行过程 它是一个动态的概念 程序可以作为一种软件资料长期存在 而进程是有一定生命期的 程序是永久的 进程是暂时的 进程更能真实地描述并发 而程序不能 进程是由进程控制块 程序段 数据段三部分组成 进程具有创建其他进程的功能 而程序没有 同一程序同时运行于若干个数据集合上 它将属于若干个不同的进程 也就是说同一程序可以对应多个进程 在传统的操作系统中 程序并不能独立运行 作为资源分配和独立运行的基本单元都是进程 通常在一个进程中可以包含若干个线程 它们可以利用进程所拥有的资源 在引入线程的操作系统中 通常都是把进程作为分配资源的基本单位 而把线程作为独立运行和独立调度的基本单位 由于线程比进程更小 基本上不拥有系统资源 故对它的调度所付出的开销就会小得多 能更高效的提高系统内多个程序间并发执行的程度 因而近年来推出的通用操作系统都引入了线程 以便进一步提高系统的并发性 并把它视为现代操作系统的一个重要指标
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!