




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
河南大学软件学院,Java编程基础,主讲:李丽,多线程,多线程基本概念创建线程的方式线程的生命周期及控制线程的优先级及调度多线程的互斥与同步守护线程(Daemon)线程组(ThreadGroup),每个任务(Task)通常就是一个程序,每个运行中的程序就是一个进程(Process),而一个程序运行时,内部又可以包含多个顺序执行流,每个执行流就是一个线程(Thread),包含多线程的应用程序称为多线程程序。而且:多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响.线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小。,多线程基本概念,classTestSingleThreadpublicstaticvoidmain(Stringargs)m1();publicstaticvoidm1()m2();publicstaticvoidm2()System.out.println(hello);,进程和线程,main方法,m1方法,m2方法,线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈,自己的局部变量,但不再拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。线程的执行时抢占式的。一个线程可以创建和撤销另一个线程。,进程和线程,Java的线程是通过Java的软件包java.lang中定义的类Thread来实现的。当生成一个Thread类的对象之后,就产生了一个线程,通过该对象实例,可以启动线程、终止线程、或者暂时挂起线程等。,创建线程的方式,创建线程的方式,(1)通过继承Thread类来创建并启动多线程的步骤:定义Thread类的子类,并重写该类的run方法,该run方法的方法体就是代表了线程需要完成的任务。因此我们经常把run方法称为线程执行体。创建Thread子类的实例,即创建线程对象。用线程对象的start方法来启动该线程。,例:CreateThread1.java,(2)实现Runnable接口来创建并启动多条线程的步骤如下:定义Runnable接口的实现类,并重写该接口的run方法,该run方法的方法体同样是该线程的线程执行体。创建Runnable实现类的实例,并以此为实例作为Thread的参数来创建Thread对象,该Thread对象才是真正的线程对象。,创建线程的方式,classSencondThreadimplementsRunnable,SencondThreadst=newSencondThread();newThread(st);,创建Thread对象时为该Thread对象指定一个名字newThread(st,”新线程1”);,例:CreateThread2.java,Thread和Runnable使用的区别,使用Runnable接口时,类不仅可以实现Runnable接口,还可以实现其它接口。使用Thread类,只能支持单继承。,线程的生命周期及控制,线程是程序内部的一个顺序控制流,它具有一个特定的生命周期。一个线程从开始到被垃圾回收器回收,首先要创建一个线程,在创建线程中,要对线程进行初始化,设置线程的终止方法。进而,线程开始执行。在执行过程中,线程有可能因为未获得足够的资源而被阻塞,也有可能因出现异常而被中断,也可能因为设置了休眠时间,而暂时停止运行。最后线程完成任务,被中止。在线程执行的过程中,因为多个线程之间要进行协调,所以线程之间的通信机制是必不可少的。否则,将会出现死锁问题。,创建状态,是指使用new运算符实例化一个线程对象,但该对象还未使用start()方法启动该对象,这个阶段只是在堆内为该对象的实例变量分配了空间,但该线程对象还无法参与抢占CPU使用权。就绪状态,实例化后的线程对象调用start()方法之后,该线程就处于了就绪状态,意味着该线程随时可以运行,它需要和其它处于就绪状态的线程通过一些算法来争夺CPU的使用权。在某一时间片里,CPU仍只能运行一个线程即正在运行的线程。一旦某个线程拥有了CPU的使用权,那么该线程也称为正在运行的线程。不可运行状态:不可运行状态包括四种情况:睡眠状态、等待状态、挂起状态和阻塞状态。一般来说,就绪状态和不可运行状态是可以相互切换的。死亡状态,一旦线程对象的run()执行完毕之后,就表明该线程进入了死亡状态(Dead)。Java虚拟机会销毁处于死亡状态的线程对象占用的系统资源。,线程的生命周期及控制,线程的生命周期及控制,创建状态,可运行状态(Runnable)thd.start();,不可运行状态(NotRunnable)线程处于可运行状态时,当下面四种情况发生,线程就进入不可运行状态:调用了sleep()方法;调用了suspend()方法;为等候一个条件变量,线程调用wait()方法;线程在等待某种资源。比如一个线程在等待某个输入输出的完成,或者线程所需要的资源被加锁,当前并不可用。,线程的生命周期及控制,调用sleep()方法使线程进入睡眠状态sleep()方法可以暂停指定线程的执行,让其它线程得到运行的机会。但调用sleep()方法会抛出InterruptedException异常,必须捕获,,sleep()方法,publicstaticvoidmain(Stringargs)for(inti=0;i10;i+)trySystem.out.println(i);Thread.sleep(1000);catch(InterruptedExceptione)e.printStackTrace();,join线程,Thread提供了让一个线程等待另一个线程完成的方法:join()方法。当在某个程序执行流中调用其它线程的join()方法时,当前线程将被阻塞,直到被join方法加入的被调线程执行完毕为止。,joinThread.java,线程让步:yield,yield()方法可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。一种完全可能的状态是:当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。,TestYield.java,死亡状态(Dead)线程的终止一般可通过两种方法实现:自然撤消或是被停止。自然撤消是指从线程的run()方法正常退出;而调用线程的实例方法stop()则可以强制停止当前线程。,/线程自然撤销publicvoidrun()inti=0;while(i=取款额)取款;余额=余额-取款额,为了解决这个问题,Java的多线程支持引入了同步监视器来解决这个问题。Synchronized可以用于方法上,让方法所包括的范围内都成为同步区域。格式如下:publicsynchronizedvoiddraw(Stringname,intmoney)-每个对象内部都有一个锁,要执行同步区域,就必须获得对象的锁。,解决异常方式:,解决异常方式:,2、使用synchronized修饰程序块synchronized(obj);通过synchronized为对象加锁,在加锁期间其它线程无法修改该资源,当该资源修改完成,该线程释放对该资源的锁定。,死锁,死锁出现的原因是线程在占有资源的同时还在等待资源,Java虚拟机没有监测,也没有采用措施来处理死锁,所以编程时应该采取措施避免死锁的出现。一旦出现死锁,整个程序既不会发生任何异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。产生死锁的原因可以归纳为2点:(1)竞争资源。当系统中有多个线程共享的资源,不能满足所有线程的需要时,引起线程之间因为争夺资源而引发死锁。(2)线程推进顺序错误。在线程的运行过程中,请求和释放资源的顺序不当,导致了线程的死锁。,TestDeadLock.java,ProducerConsumer.java,线程同步之生产者消费者问题,为了解决所出现的问题,在Java语言中可以用wait()和notify()/notifyAll()方法(在java.lang.Object类中定义)来协调线程间的运行进度(读取)关系。wait()方法的作用是让当前线程释放其所持有的“对象互斥锁”,进入wait队列(等待队列);而notify()/notifyAll()方法的作用是唤醒一个或所有正在等待队列中等待的线程,并将它(们)移入等待同一个“对象互斥锁”的队列。需要指出的是:notify()/notifyAll()方法和wait()方法都只能在被声明为synchronized的方法或代码段中调用。,线程通信,程序无法准确控制线程的轮换执行,但可以通过一些机制来保证线程协调运行。,(1)线程的协调运行可以通过Object类的wait(),notify()和notifyAll方法来协调线程运行。(2)使用管道流可以使用管道流在两个线程之间进行更多的信息交互。,例:PipeCommunicationTest.java,线程通信,使用管道流实现多线程通信的步骤:(1)创建管道输入流和管道输出流(2)使用connect方法把连个输入流和输出流连接起来。(3)将管道输入流和输出流分别传入两个线程。(4)两个线程分别依赖各自的管道输入和输出流进行通信。,通常没有必要使用管道流来控制两个线程之间的通信,因为两个线程属于一个进程,它们可以非常方便地共享数据,这种方式才是线程之间通信的最好方式,而不是管道流。,说明:,守护线程(Daemon),在客户/服务器模式下,服务器的作用是持续等待用户发来请求,并按请求完成客户的工作。,守护线程是为其它线程提供服务的线程,它一般应该是一个独立的线程,它的run()方法是一个无限循环。可以用方法publicbooleanisDaemon()确定一个线程是否守护线程,也可以用方法publicvoidsetDaemon(boolean)来设定一个线程为守护线程。守护线程与其它线程的区别是,如果守护线程是唯一运行着的线程,程序会自动退出。,一般当最后一个线程结束时,Java程序才退出守护线程的存在不影响Java程序的退出setDaemon(true)使线程成为守护线程(必须在start之前调用)setDaemon(false)使线程成为一般线程(必须在start之前调用)守护线程一般不能用于执行关键任务任务未执行完,线程就可能被强制结束守护线程一般用来做辅助性工作提示,帮助等,守护线程(Daemon),Java使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序对线程组进行控制。对线程组的控制相当于同时控制这批线程。用户创建的所有线程都属于指定线程组,如果程序没有显式指定线程属于哪个线程组,则该线程属于默认线程组。在默认情况下,子线程和创建它的父线程处于同一个线程组内。一旦某个线程加入了指定线程组之后,该线程将一直属于该线程组,直到该线程死亡,线程运行过程中不能改变它所属的线程组。,线程组,构造方法ThreadGroup(StringgroupName)ThreadGroup(ThreadGrouptg,StringgroupName)声明线程的线程组缺省创建的线程与父线程同组Thread(ThreadGrouptg,Runnablero)Thread(ThreadGrou
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 防暴徒培训基础知识课件
- 防控知识岗前培训课件
- 防控人员知识培训课件
- 防恐防暴知识培训总结课件
- 2025年高考政治总复习阶段测试卷及答案(共四套)
- 生态健康评价-洞察及研究
- 农业多模态数据可视化-洞察及研究
- 国产化精密电极头表面改性工艺与焊接质量稳定性的生命周期关联
- 可循环包装设计对供应链成本的结构性挤压
- 双碳目标下分体式制冰机的绿色制冷剂迭代路径
- 专题18形容词副词比较等级六类高考英语语法知识清单强化训练
- 全院poct管理制度
- 电动葫芦考试题及答案
- 团考试题目及答案100题
- 干眼基础试题及答案
- 政府机构的数字化转型及其领导力要求
- 艾灸治疗脾胃病的临床实践
- GB 21342-2025焦炭单位产品能源消耗限额
- 资质代办合同协议书范本
- 2023分布式能源自动发电控制与自动电压控制系统测试技术规范
- 《体重管理》课件
评论
0/150
提交评论