




已阅读5页,还剩36页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
java多线程 学习目标 线程的基本概念 线程的创建和启动 线程的调度和优先级 线程的状态控制 线程同步 多任务 多任务-在同一时刻似乎有多个程序(进程) 在同时运行的能力 多任务管理的实现方法- 抢占式多任务-直接中断而不需要事先和被中 断程序协商(UNIX/Linux,Windows NT/XP) 协作式多任务-只有在被中断程序同意交出控 制权之后才能执行中断(windows3.x和Mac OS 9 和手机) 正是由于这种多任务操作系统的出现才有了多 线程这个概念 线程概述 每个进程都有独立的代码和数据空间,进程切换到开销大 。 线程:轻量的进程,同一类线程共享代码和数据空间,每 个线程有独立的运行栈和程序计数器(标识该线程代码运 行到那个地方),线程切换的开销小 多进程:在多任务操作系统中能(同时)运行多个任务( 程序) 多线程:在同一应用程序中有多个顺序流(多个顺序流被 称为多线程)(同时)执行 注意:同时是指同一个时间段,是因为cpu把时间段分成 很多个时间片,同一个时间片运行不同的进程或线程,再 因为cpu运行的速度相当的快,所以我们感觉他们是在同 一时间内完成多个事情 每一个进程分配一块内存空间,每一个进程的多个线程共 用同一个内存 线程的创建和启动 创建线程有两种方式: 继承java.lang.Thread类 实现java.lang.Runnable接口 继承java.lang.Thread类 Thread类代表线程类,它的最主要的两个方 法是: run()-包含线程运行时所要执行的代 码,称为线程体,是线程启动的入口 start()-用于启动线程 l说明:用户定义的线程类只需要继承Thread 类,覆盖Thread类的run()方法,最后使用 start()就可以启动用户定义的线程了 Java线程模型 虚拟的CPU,由java.lang.Thread类封装和虚拟 CPU来实现。 CPU所执行的代码,传递给Thread类对象。 CPU所处理的数据,传递给Thread类对象。 代 码 数 据 虚拟CPUJava线程模型 线程例子 public class ThreadDemo1 extends Thread /* * param args */ public static void main(String args) /子线程1 ThreadDemo1 t1 = new ThreadDemo1(); /设置线程 t1.setName(“线程1“); /启动线程 t1.start(); /子线程2 ThreadDemo1 t2 = new ThreadDemo1(); t2.setName(“线程2“); t2.start(); /主线程调用 for (int i = 0; i 50; i+) System.out.println(Thread.currentThread().getName() + “=-“ + i); public void run() for (int i = 0; i 50; i+) /得到启动线程的名字 System.out.println(Thread.currentThread().getName() + “=“ + i); 启动线程 每个线程都是通过某个特定Thread对象所对应的 方法run( )来完成其操作的,方法run( )称为线程体 。 使用start()方法,线程进入Runnable(可运行)状 态,它将向线程调度器注册这个线程。 调用start()方法并不一定马上会执行这个线程,正 如上面所说,它只是进入Runnable 而不是Running 。 注意,不要直接在程序中调用线程的run()方法。 run()方法会被线程自动调用 Thread注意 ThreadDemo1 t1 = new ThreadDemo1(); t1.start(); t1.start();/报java.lang.IllegalThreadStateException异常 一个线程只能启动一次 Runnable创建线程的另一种方式 通过实现Runnable接口并实现接口中定义的 唯一方法run(),可以创建一个线程,如果 要想启动该线程就必须将实现Runnable接口 的实现类对象传递到Thread对象中,再通过 Thread中的start()方法来启动 用Runnable创建线程的例子 public class RunnableThread implements Runnable /实现接口Runnable中的run方法 public void run() for (int k = 0;k10;k+) System.out.println(“Count:“+k); 多线程共享代码和数据 多线程之间可以共享代码和数据 用例题解释 得到当前线程对象的引用 Thread类的currentThread()静态方法返回 当前线程对象的引用 两种线程创建方式的比较 使用Runnable接口 还可以从其他类继承; 保持程序风格的一致性。 直接继承Thread类 不能再从其他类继承; 编写简单,可以直接操纵线程,例如(this.getName() ) 是因为Thread类实现了Runnable接口 结束线程 线程会以以下三种方式之一结束: 线程到达其 run() 方法的末尾; 线程抛出一个未捕获到的 Exception 或 Error; 另一个线程调用一个过时的危险的 stop() 方法 (stop方法已经过期)。 线程状态 就绪状态运行状态 阻塞状态 新建 状态 start() run() 运行完毕 线程调度器 导致阻塞的事件 解除阻塞 消亡 线程状态 新建状态:使用new运算符创建一个线程后,该线 程仅仅是一个空对象,系统没有分配资源,称该线程 处于创建状态(new thread)(不调用start()方法新 创建的线程不会被启动) 就绪状态:使用start()方法启动一个线程后,系统 为该线程分配了除CPU外的所需资源,使该线程处 于可运行状态(Runnable) 运行状态:java运行系统通过调度选中一个可运 行状态的线程,使其占有CPU并转为运行中状态 (Running)或者运行一定时间后进入就绪状态重新 等待线程调度器来调度执行.此时,系统真正执行线 程的run()方法. 线程状态 阻塞状态:一个正在运行的线程因某种原 因不能继续运行时,进入阻塞状态(Blocked) 消亡:线程结束后是死亡状态(Dead) 明确让出线程的方式 调整各个线程的优先级,但是cpu不一定会按 照线程的优先级来运行,只是优先级高的 的到运行的机会多 让处于运行状态的线程调用另一个线程的 join()方法 让处于运行状态的线程调用Thread.sleep(毫 秒)方法 让处于运行状态的线程调用Thread. yield() 方法 线程的优先级 所有处于就序状态的线程根据优先级存放在可运行区,优 先级高的线程获得较多的运行机会,不是优先级高的先执 行完毕 Thread类的setPriority(int)和getPriority()方法分别用来设置 优先级和读取优先级,优先级用整数表示,取值范围是1 到10,Thread类有以下3个优先级常量值 主线程的默认优先级为5,由主线程创建的子线程的默认 优先级和主线程的优先级相等 MAX_PRIORITY 取值为10,表示最高优先级 MIN_PRIORITY 取值为1,表示最低优先级 NORM_PRIORITY 取值为5,表示默认优先级 注意:根据我多次测试,不是一定设置了最高优先级就一 定会先执行完,只是被运行的机会多 l用法举例:PriorityDemo.java 线程串行化join 当前运行的线程可以调用类的当前运行的线程的join() 方法,另一个 运行的线程将转到阻塞状态,直至当前线程运行结束,另一线程才会 恢复运行 Join相关方法介绍 join()等待该线程终止。 join(long millis) 等待该线程终止的时间最长为 millis 毫秒。 join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 lJoin()方法会抛出InterruptedException异常,如果另一个线程中断了当 前线程。当抛出该异常时,当前线程的中断状态 被清除 l用法举例: JoinDemo1.java 演示线程串行化 JoinDemo2.java 演示线程串行化实现文件先写再 读到操作 线程休眠sleep 当一个线程在运行中执行了sleep()方法时,它就会放弃CPU,转到阻 塞状态,等待指定的“延迟时间”到了就讲线程转入到就绪状态 相关方法介绍: sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停 执行)。 sleep(long millis, int nanos)在指定的毫秒数加指定的纳秒数内让当前正 在执行的线程休眠(暂停执行)。 l用法举例: SleepDemo1.java SleepDemo2.java使用sleep方法来显示时钟 线程让步yield 当线程在运行中执行了Thread类的yield()静态方法 ,如果此时具有相同优先级的其他线程处于就绪 状态,那么yield()方法将把当前运行的线程放到可 运行池中并使另一个线程运行。如果没有相同优 先级和比该线程优先级高的,则yield()方法有可能 什么都不做,但是不是一定的 相关方法介绍 yield() 暂停当前正在执行的线程对象,并执行其 他线程。 l用法举例: YieldDemo.java sleep和yield Sleep()方法会给其他线程运行的机会,而不考虑其他线程 的优先级,因此会给较低优先级线程一个运行的机会; yield()方法只会给相同优先级和更高优先级的线程一个运 行的机会,不是一个绝对的 当线程执行了sleep(long millis)方法后,将转到阻塞状态, 参数millis指定睡眠的时间,再转到就绪状态;当线程执行 了yield()方法后,将转到就绪状态 Sleep() 方法声明抛出InterruptedException异常,而yield() 方法没有声明抛出任何异常 Sleep()方法比yield()方法具有更好的可移植性。不能依靠 yield()方法来提高程序的并发性能。对于大多数程序员来 说,yield()方法的唯一用途是在测试期间人为地提高程序 的并发性能,以帮助发现一些隐藏的错误 后台线程 有一种线程,它是在后台运行的,它的任 务是为其他的线程提供服务,这种线程被 称为“后台线程(Daemon Thread)”,又称 为“守护线程“(Java的垃圾回收机制就是一 个后台线程,回收其他不再使用的内存) 后台线程的特点 后台线程与前台线程相伴相随,只有所有前台线 程都结束生命周期,后台线程才会结束生命周期 。只要有一个前台线程还没有运行结束,后台线 程就不会结束生命周期 主线程在默认情况下是前台线程,由前台线程创 建的线程默认情况下也是前台线程。调用Thread 类的setDaemon(true)方法,就能把一个线程设置 为后台线程。Thread类的isDaemon()方法用于判 断一个线程是否是后台线程 后台线程常用方法介绍 isDaemon()测试该线程是否为后台线程 setDaemon(boolean on)将该线程标记为后 台线程或用户线程 注意:主线程不可以作为后台线程 用法举例:DaemonDemo.java 与线程控制有关的方法 方法说明 start() 新建的线程进入Runnable状态 run() 线程进入Running 状态 wait() 线程进入等待状态,等待被notify,这是一个对象方法,而不是 线程方法 notify()/notifyAll() 唤醒其他的线程,这是一个对象方法,而不是线程方法 yield() 线程放弃执行,使其他优先级不低于此线程的线程有机会运行 ,它是一个静态方法 getPriority()/setPriority( ) 获得/设置线程优先级 MIN_PRIORITYNORM_PRIORITYMAX_PRIORITY suspend() 挂起该线 程,Deprecated,不推荐使用 resume() 唤醒该线 程,与suspend相对,Deprecated,不推荐使用 sleep() 线程睡眠指定的一段时间 join() 调用这个方法的主线程,会等待加入的子线程完成 多线程共享 多线程共享数据时的问题 经典的银行取款问题 有一个银行账户,还有余额1100元,现在A通过银行卡从中取1000 元,而同时另外一个人B通过存折也从这个账户中取1000元。取钱 之前,要首先进行判断:如果账户中的余额大于要取的金额,则 可以执行取款操作,否则,将拒绝取款。 我们假定有两个线程来分别从银行卡和存折进行取款操作,当A线 程执行完判断语句后,获得了当前账户中的余额数(1000元), 因为余额大于取款金额,所以准备执行取钱操作(从账户中减去 1000元),但此时它被线程B打断,然后,线程B根据余额,从中 取出1000元,然后,将账户里面的余额减去1000元,然后,返回 执行线程A的动作,这个线程将从上次中断的地方开始执行:也就 是说,它将不再判断账户中的余额,而是直接将上次中断之前获 得的余额减去1000。此时,经过两次的取款操作,账户中的余额 为100元,从账面上来看,银行支出了1000元,但实际上,银行支 出了2000元。 互斥锁 在Java语言中,引入了对象互斥锁(mutual exclusive lock,也简称为对象锁)的概念,来保 证共享数据操作的完整性: 每个对象都对应于一个可称为“互斥锁”的标记,这个标 记用来保证在任一时刻,只能有一个线程访问该对象 。 关键字synchronized 来与对象的互斥锁联系。当某个对 象用synchronized修饰时,表明该对象在任一时刻只能 由一个线程访问。 代码演示 TestSync.java和SyncDemo1.java演示线程同 步 四个线程共同来卖100张车票 TestSynchronized.java用线程同步机制和 jdbc来演示经典的银行取款问题 TestSyncUpdate.java用线程同步机制和jdbc 演示多个线程在同一个时间点上只能有一 个线程来修改数据库中的数据 关键字synchronized 在Java中的两种使用synchronized的方式: 放在方法前面,这样,调用该方法的线程均将获得 对象的锁。 放在代码块前面,它也有两种形式: synchronized (this) 代码块中的代码将获得当前对象引 用的锁 synchronized(otherObj) :代码块中的代码将获得指定 对象引用的锁 线程死锁 在synchronized使用不当的情况下就可能出 现线程死锁的问题 并发运行的多个线程间相互等待,需要对 方的对象的资源,这种无法运行的状态称 为线程死锁 预知或避开线程死锁 死锁问题 ThreadDeadLockDemo1.java 通过主线程和 子线程都要使用字符串对象和join方法来演 示死锁问题 ThreadDeadLockDemo2.java用2个子线程锁 定相互需要的对象才能执行完毕来演示死 锁问题 对象的wait()、notify()和notifyAll()方 法 Object 类定义了 wait()、notify() 和 notifyAll() 方法。可 以让线程相互通知事件的发生。要执行这些方法,必须拥 有相关对象的锁。 wait() 会让调用线程休眠,直到用 Terrupt() 中断 它、过了指定的时间、或者另一个线程用 notify() 或 notifyAll() 唤醒它。 当对某个对象调用 notify() 时,如果有任何线程正在通过 wait() 等待该
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025西医内科学考试题及答案
- 2024年高级营销师推销技巧知识试题(附含答案)
- 2025电工证考试题库及模拟考试答案低压电工考试题库高压电工考试题库
- 摩托安全知识培训
- 江西省上饶市2024-2025学年八年级下学期期末语文试题(解析版)
- 无损检测技术试题及答案
- 2025汽车买卖合同有效形式与范本
- 2025汽车销售合同范本 汽车销售合同
- 2025劳动合同范例
- 2025年福建省茶叶种植基地预约生产购销合同
- 2025届中国南方航空“明珠优才管培生”全球招聘30人笔试参考题库附带答案详解(10套)
- 2025新疆吐鲁番市法检系统面向社会招聘聘用制书记员23人考前自测高频考点模拟试题参考答案详解
- 《阿房宫赋》课件 统编版高中语文必修下册
- 2025年纪律作风测试题及答案
- 新《治安管理处罚法》培训考试题库附答案
- 银行联网核查管理办法
- 2025江苏苏州昆山国创投资集团有限公司第一期招聘17人笔试参考题库附带答案详解版
- 展会相关业务管理办法
- 安全生产网格化管理工作实施方案
- 电机维护检修培训课件
- 入场安全教育培训
评论
0/150
提交评论