Java二十三Java多线程Word文档格式.docx

上传人:b****2 文档编号:14505943 上传时间:2022-10-23 格式:DOCX 页数:19 大小:25.17KB
下载 相关 举报
Java二十三Java多线程Word文档格式.docx_第1页
第1页 / 共19页
Java二十三Java多线程Word文档格式.docx_第2页
第2页 / 共19页
Java二十三Java多线程Word文档格式.docx_第3页
第3页 / 共19页
Java二十三Java多线程Word文档格式.docx_第4页
第4页 / 共19页
Java二十三Java多线程Word文档格式.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

Java二十三Java多线程Word文档格式.docx

《Java二十三Java多线程Word文档格式.docx》由会员分享,可在线阅读,更多相关《Java二十三Java多线程Word文档格式.docx(19页珍藏版)》请在冰豆网上搜索。

Java二十三Java多线程Word文档格式.docx

程不可以直接访问其他进程的地址空间。

动态性:

进程与程序的区别在于,程序

知识一个静态的指令集合,而进程是一个正在系统中活动的指令集合。

在进程中加

入了时间的概念。

进程具有自己的生命周期和各种不同的状态,这些概念在程序中

都是不具备的。

并发性:

多个进程可以在单个处理器上并发执行,多个进程之间

不会互相影响。

注意:

并发性(concurrency)和并行性(parallel)是两个概念。

并行指在同一时刻,有多条指令在多个处理器上同时执行;

并发指在同一时刻只

能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程

同时执行的效果。

 现代的操作系统都支持多进程的并发,但在具体的实现细节上可能因为硬件和

操作系统的不同而采用不同的策略。

比较常用的方式有:

共用式的多任务操作策

略,例如Windows3.1和MacOS9;

目前操作系统大多采用效率更高的抢占式多

任务操作策略,例如WindowsNT、Windows2000以及UNIX/Linux等操作系统。

 多线程则扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。

线程(Thread)也被称作轻量级进程(LightweightProcess),线程是进程的执行单

元。

就像进程在操作系统中的地位一样,线程在程序中是独立的、并发的执行流。

当进程被初始化后,主线程就被创建了。

对于绝大多数的应用程序来说,通常仅要

求有一个主线程,但也可以在该进程内创建多条顺序执行流,这些顺序执行流就是

线程,每个线程也是相互独立的。

 2.多线程的优势线程在程序中是独立的、并发的执行流,与分隔的进程相

比,进程中线程之间的隔离程度要小。

它们共享内存、文件句柄和其他每个进程应

有的状态。

当操作系统创建一个进程时,必须为该进程分配独立的内存空间,并

分配大量的相关资源;

但创建一个线程则简单得多,因此使用多线程来实现并发比

使用多进程实现并发的性能要高得多。

 总结起来,使用多线程编程具有如下几个有点:

 进程之间不能共享内存,但线程之间共享内存非常容易。

系统创建进程时需

要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现

多任务并发比多进程的效率高。

Java语言内置了多线程功能支持,而不是单纯地

作为底层操作系统的调度方式,从而简化了Java的多线程编程。

二、线程的创建

和启动Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子

类的实例。

每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段

顺序执行的代码)。

Java使用线程执行体来代表这段程序流。

 1.继承Thread类创建线程类通过继承Thread类来创建并启动多线程的步骤如

下:

1.定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就

代表了线程需要完成的任务。

因此把run()方法称为线程执行体。

2.创建Thread子

类的实例,即创建了线程对象。

3.调用线程对象的start()方法来启动该线程。

 2.实现Runnable接口创建线程类实现Runnable接口来创建并启动多线程的步

骤如下:

-定义Runnable接口的实现类,并重写该接口的run()方法,该run()方

法的方法体同样是该线程的线程执行体。

-创建Runnable实现类的实例,并以此

实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对

象。

-调用线程对象的start()方法来启动该线程

 3.使用Callable和Future创建线程前面已经指出,通过实现Runnable接口创

建多线程时,Thread类的作用就是把run()方法包装成线程执行体。

那么是否可以直

接把任意方法都包装成线程执行体呢?

Java目前不行!

但Java的模仿者C#可以

(C#可以把任意方法包装成线程执行体,包括有返回值的方法)。

 也许受此启发,从Java5开始,Java提供了Callable接口,该接口怎么看都像

是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行

体,但call()方法比run()方法功能更强大。

 call()方法可以有返回值call()方法可以声明抛出异常因此完全可以提供一个

Callable对象作为Thread的target,而该线程的线程执行体就是该Callable对象的

call()方法。

问题是:

Callable接口是Java5新增的接口,而且它不是Runnable接口

的子接口,因此Callable对象不能直接作为Thread的target。

而且call()方法还有一

个返回值——call()方法并不是直接调用,它是作为线程执行体被调用的。

那么如何

获取call()方法的返回值呢?

Java5提供了Future接口来代表Callable接口里call()

方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了

Future接口,并实现了Runnable接口——可以作为Thread类的target。

 创建并启动有返回值的线程的步骤如下:

 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行

体,且该call()方法有返回值,再创建Callable实现类的实例。

从Java8开始,可以

直接使用Lambda表达式创建Callable对象使用FutureTask类来包装Callable对

象,该FutureTask对象封装了该Callable对象的call()方法的返回值使用

FutureTask对象作为Thread对象的target创建并启动新线程。

调用FutureTask对

象的get()方法来获得子线程执行结束后的返回值。

4.创建线程的三种方式对比

采用实现Runnable、Callable接口的方式创建多线程的优缺点:

-线程类只是实现

了Runnable接口或Callable接口,还可以继承其他类。

-在这种方式下,多个线

程可以共享同一个target对象,因此非常适合多个相同线程来处理同一份资源的情

况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象

的思想。

-劣势是,编程稍稍复杂,如果需要访问当前线程,则必须使用

Thread.currentThread()方法。

 采用继承Thread类的方式创建多线程的优缺点:

 劣势是,因为线程类已经继承了Thread类,因此不能再继承其他父类优势

是,编写简单,如果需要访问当前线程,则无须使用Thread.currentThread()方法,

直接使用this即可获得当前线程鉴于上面分析,因此一般推荐采用实现Runnable

接口、Callable接口的方式来创建多线程。

 三、线程的声明周期当线程被创建并启动以后,它既不是已启动就进入了执

行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New)、

就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。

其是当线程启动以后,它不可能一直“霸占”着CPU独自运行,因此CPU需要在多

条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

 1.新建和就绪状态当程序使用new关键字创建了一个线程之后,该线程就处

于新建状态,此时它和其他的Java对象一样,仅仅由Java虚拟机为其分配内存,

并初始化其成员变量的值。

此时的线程对象没有表现成任何线程的动态特征,程序

也不会执行线程的线程执行体。

 当线程对象调用了start()方法之后,该线程就处于就绪状态,Java虚拟机会为

其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始执行,只是表

示该线程可以运行了。

至于该线程何时开始运行,取决于JVM里线程调度器的调

度。

 注意启动线程使用start()方法,而不是run()方法!

永远不要调用线程对象的

run()方法!

调用start()方法来启动线程,系统会把该run()方法当成线程执行体来处

理;

但如果直接调用线程对象的run()方法,则run()方法立即就会被执行,而且在

run()方法返回之前其他线程无法并发执行——也就是说,如果直接调用线程对象的

run()方法,系统把线程对象当成一个普通对象,而run()方法也是一个普通方法,而

不是线程执行体。

 调用线程对象的start()方法之后,该线程立即进入就绪状态,但并未进入运行

状态。

如果希望调用子线程的start()方法后子线程立即开始执行,程序可以使用

Thread.sleep

(1)来让当前运行的线程(主线程)睡眠1毫秒。

这样就可以让子线程立

即开始执行。

 2.运行和阻塞状态如果处于就绪状态的线程获得了CPU,开始执行run()方法

的线程执行体,则该线程处于运行状态。

当发生如下情况时,线程将会进入阻塞

状态

 线程调用sleep()方法主动放弃所占用的处理器资源。

线程调用了一个阻塞式

IO方法,在该方法返回之前,该线程被阻塞。

线程试图获得一个同步监视器,但

该同步监视器正被其他线程所持有。

线程在等待某个通知(notify)程序调用了

线程的suspend()方法将该线程挂起。

但这个方法容易导致死锁,因此应该尽量避免

使用该方法。

被阻塞的线程会在合适的时候重新进入就绪状态,注意是就绪状

态,而不是运行状态。

 针对上面几种情况,当发生如下特定的情况时可以解除上面的阻塞,让该线程

重新进入就绪状态。

 调用sleep()方法的线程经过了指定时间线程调用的阻塞式IO方法已经返回。

线程成功地获得了试图取得的同步监视器线程正在等待某个通知时,其他线程发

出了一个通知。

处于挂起状态的线程被调用了resume()恢复方法下图显示了线

程状态转换图3.线程死亡线程会以如下三种方式结束,结束后处于死亡状

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 计算机软件及应用

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

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