Java多线程基本概念
基本概念
线程与任务的概念不一样。
任务:通常是一些抽象的且离散的工作单元,比如在Web请求中,针对用户的请求需要返回相应的页面是一个任务,在Java
中实现Runnable
接口的类也是一个任务.
线程:执行任务的实体,可以在单个线程中串行地执行各项任务,例如单线程串行执行Web请求,也可以在为每个请求建立一个线程执行。
任务是一组逻辑工作单元,而线程则是使任务异步执行的机制。
一个简单的例子:当我们定义了一个Runnable
对象时,即任务,使用new Thread(Runnable).start()
即将任务放到实际的线程中执行。
Executor线程池
Web应用中有两种执行任务的策略:
把所有任务放在单个线程中串行执行:糟糕的响应性和吞吐量。
为每个任务创建一个线程并行的执行:资源管理的复杂性,体现在线程开销大,不稳定。
所以在Java
中引入了Executor
(线程池)框架来简化线程的管理工作,Executor
使用Runnable作为其基本的任务表示形式,在Java
类库中,任务执行的主要抽象不是Thread
,而是Executor
。
Executor
基于生产者-消费者模式,提交任务的操作相当于生产者(生成待完成的工作单元),执行任务的线程则相当于消费者(执行完这些工作单元),这样就将请求处理任务的提交与任务的实际执行解耦开来。在下面例子中建立一个固定长度的线程池,可以容纳100个线程。
class TaskExecutionWebServer {
private static final int NTHREADS = 100;
// 调用Executors中的静态工厂方法可以来创建一个线程池
private static final Executor exec =
Executors.newFixedThreadPool(NTHREADS);
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
// 通过execute将任务提交到工作队列中,工作线程反复获取执行
exec.execute(task);
}
}
}
执行策略
线程池是指管理一组同构工作线程的资源池。通过重用现有的线程而不是创建新线程,可以在处理多个请求时,分摊在线程创建和销毁过程中产生的巨大开销。另一个额外的好处是,当请求到达时,工作线程已经存在,因为提高了响应性。
- 工作队列(Work Queue):线程池是与工作队列密切相关的,其中在工作队列中保存了所有等待执行的任务。
- 工作者线程(Worker Thread):从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。
在执行策略中定义了任务执行的“What、Where、When、How”等方面,包括:
- 该任务在哪个线程中执行
- 任务可以按照什么样的顺序来执行(如优先级、FIFO、LIFO)
- 有多少个任务可以并发执行
- ......
生命周期
线程池生命周期(ExecutorService)
我们已经知道了如何创建一个Executor,但并没有讨论如何关闭它。为了解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理方法。
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
//...
}
ExecutorService的生命周期有3种状态:运行、关闭和已终止。shutdown()方法将执行平缓的关闭过程:不再接受新的任务,同时等待已提交任务执行完成(包括未开始执行的任务)。shutdownNow()将尝试取消所有运行的任务。关闭后再提交,由“拒绝执行处理器”处理,或者抛出RejectedExecutionException异常。
任务生命周期(Future)
由于Runnable不能返回一个值或者抛出一个受检查的异常,存在着很大的局限性。所以引入了Callable,它认为主入口点(即call)将返回一个值,并可能抛出一个异常。
又Runnable和Callable描述都是抽象的计算任务,通常经过创建、提交、开始和完成四个阶段,就如ExecutorService为Executor解决生命周期问题,Future也为一个任务解决了生命周期的问题,并提供了相应地方法来判断是否已经完成或取消,以及获取任务的结果和取消任务。
public interface Callable<V> {
V call() throws Exception;
}
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning); // 取消任务
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionExeception,
CancellationExeception;
V get(long timeout, TimeUnit unit) throws
InterruptedException, ExecutionExeception
CancellationExeception, TimeoutException;
通过调用ExecutorService中得submit方法将返回一个Future代表该任务的生命周期,可用来获得任务的执行结果或者取消任务。也可以显示地为某个指定的Runnable或Callable实例化一个FutureTask。
在将Runnable或Callable提交到Executor的过程中,包含了一个安全发布的过程,即将Runnable或Callable从提交线程发布到最终执行任务的线程。类似地,在获取Future结果的过程中也包含了一个安全发布,即将这个结果从计算它的线程发布到任何通过get获得它的线程。
参考: 书本Java Concurrency in Practice
Java多线程基本概念的更多相关文章
- Java多线程--基础概念
Java多线程--基础概念 必须知道的几个概念 同步和异步 同步方法一旦开始,调用者必须等到方法调用返回后,才能执行后续行为:而异步方法调用,一旦开始,方法调用就立即返回,调用者不用等待就可以继续执行 ...
- Java多线程编程— 概念以及经常使用控制
多线程能满足程序猿编写很有效率的程序来达到充分利用CPU的目的,由于CPU的空暇时间可以保持在最低限度.有效利用多线程的关键是理解程序是并发运行而不是串行运行的.比如:程序中有两个子系统须要并发运行, ...
- Java多线程——锁概念与锁优化
为了性能与使用的场景,Java实现锁的方式有非常多.而关于锁主要的实现包含synchronized关键字.AQS框架下的锁,其中的实现都离不开以下的策略. 悲观锁与乐观锁 乐观锁.乐观的想法,认为并发 ...
- Java多线程常见概念
进程和线程的区别 进程是资源分配的最小单位,线程是CPU调度的最小单位 线程不能看做独立应用,而进程可以 进程有独立的地址空间,互相不影响,线程只是进程的不同执行路径 线程没有独立的地址空间,多进程的 ...
- Java多线程概念及优缺点,多线程的地位|乐字节
大家好,乐字节小乐有来咯,上次说完了Java网络编程探究|乐字节,这次我们来看看线程相关的吧. Java线程主要讲述的内容有: 1.线程概念 多线程,说白了就是多条执行路径,原来是一条路径,就主路径( ...
- Java多线程初学者指南系列教程
转自:http://developer.51cto.com/art/200911/162925.htm 51cto 本系列来自NokiaGuy的“真的有外星人吗”博客,系列名称为<Java多线程 ...
- Java多线程<1>
1.Java多线程的概念: 线(Thread):它指的是一个任务的从开始执行流程到结束. 穿线提供执行任务的机构.供java条款.在一个程序可以启动多个并发线程.候执行. 在单处理器系统中,多个线程共 ...
- Java多线程编程(学习笔记)
一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...
- 深度解析Java多线程的内存模型
内部java内存模型 硬件层面的内存模型 Java内存模型和硬件内存模型的联系 共享对象的可见性 资源竞速 Java内存模型很好的说明了JVM是如何在内存里工作的,JVM可以理解为java执行的一个操 ...
随机推荐
- [MAC]2015款MACBOOK使用BOOTCAMP安装WIN8.1+多分区
注意事项: 2013年以前,带光驱的,请使用WinClone安装WIN7或WIN8,或可使用BOOTCAMP制作WINDOWS安装光盘 13-14年,不带光驱的,也能使用WinClone安装WIN7和 ...
- 使用openssl实现ECDSA签名以及验证功能(附完整测试源码)
突然找到数年前写的这段代码,当是因为对密码学几乎不怎么了解踩了一些坑,现在开源出来方便大家直接利用. ECDSA的全名是Elliptic Curve DSA,也就是椭圆曲线DSA,由于椭圆曲线的复杂性 ...
- javascript算法
代码运行环境: nodejs + mochajs /* *选择排序 *每次查找数组最小数据 *将最小数据排到左侧 */ var assert = require('assert'); describe ...
- 并发下常见的加锁及锁的PHP具体实现-转载
并发下常见的加锁及锁的PHP具体实现 http://www.cnblogs.com/scotoma/archive/2010/09/26/1836312.html 在最近的项目中有这样的场景 1.生成 ...
- Avalon接口协议
Avalon接口协议 https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/manual/mnl_ava ...
- SRM 146 DIV2 1000
Problem Statement A well-known riddle goes like this: Four people are crossing an old bridge. T ...
- UCS2和UTF16有区别
UCS2是定长的,固定2个字节,所以不能支持扩展字符,而UTF16是变长的. UCS2是落伍的. msdn里有这样一段描述: UCS-2 is a predecessor of UTF-16. ...
- 一步一步学WebSocket (一) 初识WebSocket
众所周知,Http协议是无状态的,并且是基于Request/Response的方式与服务器进行交互,也就是我们常说的单工模式.但是随着互联网的发展,浏览器与服务端进行双向通信需求的增加,长轮询向服务器 ...
- 误差曲线(Matlab)
loglog(dof(:),errorestimate(:),:),errorestimate1(:),);hold on; loglog(dof(:),eigvalue(:)-[);%[13.086 ...
- 建筑材料系统 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发
框架介绍: 1.基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发 2.采用MVC的框架模式,具有耦合性低.重用性高.生命周期成本低.可维护性 ...