ImageVerifierCode 换一换
格式:DOCX , 页数:45 ,大小:83.83KB ,
资源ID:11215625      下载积分:10 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11215625.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(高清版21天学通JAVA第十三天.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

高清版21天学通JAVA第十三天.docx

1、高清版21天学通JAVA第十三天第13章多线程 多线程是Java中的并发机制,表示能够在同一时间内同时执行多个操作。在日常生活中,边上网边听歌就是一个多线程。随着CPU进入双核,甚至多核时代,多线程的优势越来越明显。Java本身就是一门支持多线程的语言,在Java中使用多线程是很方便的,同样也是很高效的。通过本章的学习,读者应该能够完成如下几个目标。 了解什么是多线程。 熟练掌握如何定义和使用多线程。 了解多线程的生命周期。 掌握多线程的调用的几个情况。 了解多线程的同步问题。 1-1 13.1 多线程简介 多线程就好像日常生活中同时做几件事一样,例如早上起床,要烧水洗脸,在烧水时就可以刷牙,

2、还可以边刷牙边看早间新闻,这样就同时做着烧水、刷牙、看电视三件事。多线程也是一样的,在同一时刻有可能在执行多个线程,这样能够更好地提高办事效率。 在实际开发中也是在很多地方使用多线程的,例如在很多网站中,当用户注册后,系统一方面会通知用户已经注册成功,一方面向用户在注册时填写的Email中发送邮件。这里就需要使用多线程,如果使用的是单线程,系统就会向用户注册的Email中发送邮件后才显示用户注册成功,由于发送邮件可能需要很长的时间,从而影响整个注册进度。 在前面的学习中,虽然没有使用多线程,但是同样使用到了线程的知识。在每一个程序中的main方法就是一个线程,它一般被称为主线程。在主线程中可以

3、启动多个子线程来执行。 1-2 13.2 定义线程和创建线程对象 在上一小节中讲解了什么是多线程,在本节中就来讲解怎样来定义线程和如何创建线程对象。定义线程有两种方法,一种是继承Thread类,一种是实现Runnable接口,这两种方法是存在各自优缺点的。和定义线程对应的就是创建线程对象,也是有两种方法。在本节中就来学习使用这两种方法来定义线程,以及相对应的创建线程对象。 1-3 13.2.1 继承Thread类定义线程 定义一个线程可以通过继承Thread类来实现,这是一种相对简单的定义线程的方法。在Thread类中具有一个run方法,在定义的线程中需要重写这个方法。在重写的run方法中,可

4、以定义该线程所要执行的语句。当线程启动时,run方法中的程序就成为一条独立的执行线程。 【范例】示例代码是一个通过继承Thread类定义线程的程序。 示例代码 01 public class XianCheng1 extends Thread 02 03 public void run() 04 05 System.out.println(通过继承Thread定义线程); 06 07 1-4 1-5该程序是无法运行的,因为没有main方法,也就是没有启动线程的方法。在该程序中创建了一个线程类继承于Thread类,并且在该类中重写了run方法,在其中定义了该线程的功能是显示一条语句。注意:重写的

5、run方法也是可以作为一般的方法来调用的,但是这种调用并不是作为一个线程出现的,它只是主线程中的一部分。同样,run方法也是可以被重载的,但是重载后的run方法不作为一个线程,也是主线程的一部分。讲解完定义线程后,就可以来学习如何创建线程对象。通过继承Thread类创建线程,是很容易创建线程对象的。在这种定义线程的方法中,创建线程对象和创建普通对象是一样的。下面是创建示例代码13-1中线程对象的代码。XianCheng1 xc=new XianCheng1();从创建线程对象的程序可以看出,创建线程对象的方法和创建普通对象的方法是一样的。但是这只是对于使用继承Thread类创建线程的方法来说的

6、。 13.2.2 实现Runnable接口定义线程1-6定义线程除了通过继承Thread类来实现,还可以通过实现Runnable接口来实现。在Runnable接口中具有一个抽象的run方法,在实现Runnable接口时,需要实现该run方法。该run方法就会作为一个执行线程的方法。【范例】示例代码是一个通过实现Runnable接口定义线程的程序。 示例代码01 public class XianCheng2 implements Runnable02 03 public void run()04 05 System.out.println(通过实现Runnable接口定义线程);06 07 1

7、-71是通过继承Thread类定义线程,2是通过实现Runnable接口来定义线程。这两种方法中都需要定义一个run方法,不管该方法是通过重写父类方法,还是实现接口方法。run方法是一个线程的入口,是线程必须具有的。在使用通过实现Runnable接口定义的线程中,要想创建线程对象就不是很容易做到的。因为直接创建类对象,创建的并不是一个线程对象。要想创建线程对象,必须要借助Thread类。Thread类具有4个构造器,最常用的就是具有一个参数,该参数是实现Runnable接口类对象的构造器。创建线程对象的程序如下所示。XianCheng2 xc=new XianCheng2();Thread t

8、=new Thread(xc);在该程序中,首先创建了一个实现Runnable接口的类对象,然后将该对象作为Thread类的参数,从而创建了一个线程对象。创建的类对象是可以作为多个Thread类构造器参数的,这样就创建了多个线程。这一点将在以后的学习中多次使用。 13.3 运行线程 在上一节中学习了如何定义线程,并且知道了如何创建线程对象。对这些都了解后就需要来学习如何运行线程。在本节中分为两个小节来讲解,先来学习如何启动线程,然后讲解如何运行多个线程。 1-8 13.3.1 启动线程1-9有些读者会认为启动线程就是调用线程类中的run方法。例如示例代码13-3中所演示的。【范例】示例代码是一

9、个错误的启动线程的程序。 示例代码01 class MyRunnable implements Runnable02 03 /定义一个run线程方法04 public void run()05 06 System.out.println(这是一个错误的启动线程的程序);07 08 09 public class XianCheng310 11 public static void main(String args)12 13 MyRunnable mr=new MyRunnable();14 mr.run(); /调用run方法15 16 从该程序可以看出,run方法是可以通过方法调用来执行的

10、,但是这并不代表创建了一个新线程。这是一个错误的启动线程的方法。 如果想正确地启动一个线程,需要调用线程对象的start方法,下面通过程序来演示如何正确的启动一个线程。 1-10 一个正确的启动线程的程序0102030405060708091011121314class MyRunnable implements Runnable/定义一个run线程方法public void run()System.out.println(这是一个正确的启动线程的程序);public class XianCheng4public static void main(String args)MyRunnable

11、mr=new MyRunnable();Thread t=new Thread(mr);151617t. start ();/启动线程 1-11 【代码解析】第一次看到该程序时,读者可能会感到有些奇怪,为什么调用的是start方法,而执行的是run方法,这就是Java对多线程的设计。在调用start方法后,就启动了线程,该线程是和main方法并列执行的线程。这样该程序就变为一个多线程程序。 注意:线程只能被启动一次,也就是只能调用一次start方法。当多次启动线程,也就是多次调用start方法时,就会发生异常。 1-12 13.3.2 同时运行多个线程 学习了如何启动线程,接下来就来学习如何同

12、时运行多个线程。首先通过示例代码来看一下如何同时运行多个线程。 27 28 29 30 31 32public static void main(String args)MyRunnable1 mr1=new MyRunnable1();MyRunnable2 mr2=new MyRunnable2();Thread t1=new Thread(mr1);Thread t2=new Thread(mr2); 33 34 35t1.start();t2.start();/启动第一个线程/启动第二个线程 36 1-13 【代码解析】在示例代码13-6中首先定义了两个实现Runnable接口的类,在

13、两个类中都定义了run方法,显示多个不同的符号。从运行结果中可以看出,不同的符号是交替显示的。 在同时运行多个线程时,运行结果不是唯一的,因为有很多不确定的因素。首先先执行哪一个线程就是不确定的,线程间交替也是不确定的。但是确定的是每一个线程都将启动,每一个线程都执行结束。 1-14 13.4 线程生命周期 线程是存在生命周期的。线程的生命周期分为五种不同的状态,分别是新建状态、准备状态、运行状态、等待/阻塞状态和死亡状态。在本节中就来对每一个状态进行讲解。 1-15 13.4.1 新建状态 当一个线程对象被创建后,线程就处于新建状态。在新建状态中的线程对象从严格意义上看还只是一个普通的对象,

14、它还不是一个独立的线程。处于新建状态中的线程被调用start方法后就会进入准备状态。从新建状态中只能进入准备状态,并且不能从其他状态进行新建状态。新建状态是线程生命周期的第一个状态。 1-16 13.4.2 准备状态 处于新建状态中的线程被调用start方法就会进入准备状态。处于准备状态下的线程随时都可能被系统选择进入运行状态,从而执行线程。可能同时有多个线程处于准备状态,对于哪一个线程将进入运行状态是不确定的。线程从新建状态进入到准备状态后是不可能再进入新建状态的。在等待/阻塞状态中的线程被解除等待和阻塞后将不直接进入运行状态,而是首先进入准备状态,让系统来选择哪一个线程进入运行状态。 1-

15、17 13.4.3 运行状态 处于准备状态中的线程一旦被系统选中,使线程获取了CPU时间,就会进入运行状态。在运行状态中将执行线程类run方法中的程序语句。线程进入运行状态后也不是一下执行结束的,线程在运行状态下随时都可能被调度程序调度回准备状态。在运行状态下还可以让线程进入到等待/阻塞状态。在通常的单核CPU中,在同一时刻只有一个线程处于运行状态的。在多核的CPU中,就可能两个线程或者更多的线程同时处于运行状态,这也是多核CPU运行速度快的原因。 1-18 13.4.4 等待/阻塞状态 在Java中定义了许多线程调度的方法,包括睡眠、阻塞、挂起和等待,这些方法将在后面的调度章节中讲解。使用这

16、些方法都会将处于运行状态的线程调度到等待/阻塞状态。处于等待/阻塞状态的线程被解除后,不会立即回到运行状态,而是首先进入准备状态,等待系统的调度。 1-19 13.4.5 死亡状态 当线程中的run方法执行结束后,或者程序发生异常终止运行后,线程会进入死亡状态。处于死亡状态的线程不能再使用start方法启动线程,这在前面的学习中已经学到了这一点。但是这不代表处于死亡状态的线程不能再被使用,它也是可以再被使用的,只是将被作为普通的类来使用。 注意:线程生命周期的问题,有些读者会觉得很容易的。线程生命周期的问题在后面的学习中会经常使用到,只有能充分了解线程的生命周期,才能更好地理解后面的内容。 1

17、-20 13.5 线程的调度 通过系统自动调度,线程的执行顺序是没有保障的。在Java中定义了一些线程调度的方法,使用这些方法在一定程序上对线程进行调度,使用这些方法只是给线程一个建议,具体是否能够成功,也是没有保障的。线程调度的方法有几个,包括睡眠方法、设置优先级、让步方法等,在本节中就来学习这些方法的使用。 1-21 13.5.1 睡眠方法 当线程处于运行状态时,调用sleep睡眠方法将使线程从运行状态进入等待/阻塞状态,从而使程序停止运行。sleep睡眠方法是具有一个时间参数的,当经过这么长时间后,线程将进入准备状态,等待系统的调度。从而可以看出,当线程调用睡眠方法后,要想回到运行状态,

18、需要的时间要比指定的睡眠时间长。 sleep方法被重载,存在两种形式,sleep方法的基本语法格式如下所示。 public static void sleep(long millis)throwsInterruptedException; public static void sleep(long millis,int nanos)throwsInterruptedException; 1-22 使用这两个sleep方法都能使线程进入睡眠状态,mills参数表示线程睡眠的毫秒数,nanos参数表示线程睡眠的纳秒数。sleep方法是一个静态的方法,所以sleep方法不是依赖于某一个对象的,它的位

19、置是比较随意的。当在线程中执行sleep方法,则该线程就进入睡眠状态。要想让某一个线程进入睡眠状态,并不是让该线程调用sleep方法,而只是让该线程执行sleep方法。sleep方法是可能发生捕获异常的,所以在使用sleep方法时必须进行异常处理。 注意:sleep方法只是给线程一个调度的建议,是否调度成功是不能确定的。在该程序中只有两个线程,所以运行结果出现交替显示的结果。当程序中存在多个线程时,运行结果就可以发生变化,甚至出现意外的结果。 1-23 13.5.2 线程优先级 在大部分的系统中,对进程的调度都是采用优先级的方式来进行的。在Java中对线程进行调度时,也是可以采用优先级来调度的

20、。不同的线程可以具有不同的优先级,优先级高的线程就会占用更多的CPU资源和被执行概率。 Java中的优先级是采用从1到10来表示的,数字越大表示优先级越高。如果没有为线程设置优先级,则线程的优先级为5,这也是线程的默认值。但是对于子线程来说,它的优先级是和其父线程优先级相同的。 当需要对线程的优先级进行设置时,可以通过调用setPriority方法来设置。setPriority方法的语法格式如下所示。 public final void setPriority(int i); 其中参数i表示的就是优先级的等级数,它可以从1到10。除了可以使用数字来表示优先级,Java还在Thread类中定义了

21、三个表示优先级的常量。MAX_PRIORITY表示线程的最高优先级,NORM_PRIORITY表示线程的默认优先级,MIN_PRIORITY表示线程的最低优先级。 1-24 13.5.3yield让步方法 在Java中具有两种线程让步方法,先来介绍第一种yield让步方法。yield让步方法是让线程让出当前CPU,而将CPU让给哪一个线程是不确定的,由系统来进行选择。使用yield让步方法的线程将从运行状态进入到准备状态。 注意:yield让步操作是可能不成功的。因为在线程中使用yield方法,使该线程进入准备状态。但是系统是有可能再次选择该线程,使该线程进入运行状态的。 yield让步方法的

22、基本语法格式如下所示。 public static void yield(); 可以看出yield让步方法是一个静态方法,所以该方法也是和对象无关的。当在正在运行的线程中运行该方法时,该线程将回到准备状态。 1-25 13.5.4join让步方法1-26使用join让步方法,可以将当前线程的CPU资源让步给指定的线程。join让步方法的语法格式如下所示。public final void join()throws InterruptedException;public final void join(long mills)throws InterruptedException;public f

23、inal void join(long millis,int nanos)throwsInterruptedException;join让步方法是具有三种形式的,没有参数表示指定的线程执行完成后再执行其他线程,参数表示在参数的时间内执行让步给的执行线程。join让步方法也是可能发生捕获异常的,所以在使用时要进行异常处理。 13.6 综合练习1-271.判断下面程序是否能够正常运行。01 public class LianXi1 extends Thread02 03 public void run()04 05 for(int i=0;i5;i+)06 07 System.out.printl

24、n(i);08 09 10 public static void main(String args)11 12 LianXi1 lx=new LianXi1();13 lx.run();14 15 13.6 综合练习1-282.判断下面的程序是否能够正常运行。01 public class LianXi2 extends Thread02 03 public void run()04 05 for(int i=0;i5;i+)06 07 Thread.sleep(100);08 09 10 public static void main(String args)11 12 LianXi1 lx=new LianXi1();13 lx.run();14 15 13.7 小结 在本章中学习了Java中的多线程,首先对线程进行了简单的介绍,然后讲解如何定义、创建和运行多线程。接下来还讲解了线程的生命周期和对线程的调度。 1-29

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1