Java Executor 框架学习总结
大多数并发都是通过任务执行的方式来实现的。一般有两种方式执行任务:串行和并行。
class SingleThreadWebServer {
public static void main(String[] args) throws Exception {
ServerSocket socket = new ServerSocket(80);
while(true) {
Socket conn = socket.accept();
handleRequest(conn);
}
}
}
class ThreadPerTaskWebServer {
public static void main(String[] args) throws Exception {
ServerSocket socket = new ServerSocket(80);
while(true) {
final Socket conn = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(conn);
}
};
new Thread(task).start();
}
}
}
当然上面的这两种方式都是有问题的。单线程的问题就是并发量会是瓶颈,多线程版本就是无限制的创建线程会导致资源不足问题。
Executor 框架
任务是一组逻辑工作单元,而线程是使任务异步执行的机制。
JDK 提供了 Executor 接口:
public interface Executor {
void execute(Runnable command);
}
虽然 Executor 接口比较简单,但是却是异步任务执行框架的基础,该框架能支持多种不同类型的任务执行策略。它提供了一种标准的方式把任务的提交过程与执行过程进行了解耦。用 Runnable 来代表任务。Executor 的实现提供了对生命周期的支持以及统计信息应用程序管理等机制。
Executor 是基于生产者消费者模式的,提交任务的操作相当于生产者,执行任务的线程相当于消费。
基于 Executor 的 WebServer 例子如下:
public class TaskExecutorWebServer {
private static final int NTHREADS = 100;
private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(80);
while (true) {
final Socket conn = serverSocket.accept();
Runnable task = new Runnable() {
@Override
public void run() {
handleRequest(conn);
}
};
exec.execute(task);
}
}
}
另外可以自己实现 Executor 来控制是并发还是并行的,如下面代码:
/**
* 执行已提交的 Runnable 任务的对象。
* 此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。
* 通常使用 Executor 而不是显式地创建线程。
*
*
* @author renchunxiao
*
*/
public class ExecutorDemo {
public static void main(String[] args) {
Executor executor = new ThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
// do something
}
});
Executor executor2 = new SerialExecutor();
executor2.execute(new Runnable() {
@Override
public void run() {
// do something
}
});
}
}
/**
* 创建一个线程来执行 command
*
* @author renchunxiao
*
*/
class ThreadExecutor implements Executor {
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}
/**
* 串行执行 command
*
* @author renchunxiao
*
*/
class SerialExecutor implements Executor {
@Override
public void execute(Runnable command) {
command.run();
}
}
线程池
线程池就是线程的资源池,可以通过 Executors 中的静态工厂方法来创建线程池。
- newFixedThreadPool。创建固定长度的线程池,每次提交任务创建一个线程,直到达到线程池的最大数量,线程池的大小不再变化。
- newSingleThreadExecutor。单个线程池。
- newCachedThreadPool。根据任务规模变动的线程池。
- newScheduledThreadPool。创建固定长度的线程池,以延迟或定时的方式来执行任务。
JVM 只有在所有非守护线程全部终止后才会退出,所以,如果无法正确的关闭 Executor,那么 JVM 就无法结束。
为了解决执行服务的生命周期问题,有个扩展 Executor 接口的新接口 ExecutorService。
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService 生命周期有三种状态:运行、关闭、已终止。ExecutorService 在初始创建时处于运行状态。shutdown 方法会平缓关闭:不在接受新的任务,并且等待已经执行的任务执行完成(包括那些还未开始的任务)。shutdownNow 方法将粗暴关闭:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始的任务。所有任务都执行完成后进入到已终止状态。
Callable 和 Future
Executor 框架使用 Runnable 作为基本的任务表示形式。Runnable 是一种有局限性的抽象,它的 run 方法不能返回值和抛出一个受检查异常。
许多任务实际上是存在延时的计算,例如数据库查询,从网络获取资源。对于这些任务,Callable 是更好的抽象,它认为 call 将返回一个值,并且可能抛出异常。
Executor 执行的任务有四个生命周期阶段:创建、提交、开始和完成。由于有些任务需要很长时间有可能希望取消,在 Executor 框架当中,已提交未开始的任务可以取消。
Future 表示一个任务的生命周期,并且提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。
Java Executor 框架学习总结的更多相关文章
- Java Executor 框架
Java Executor 框架 Executor框架是指java5中引入的一系列并发库中与executor相关的功能类,包括Executor.Executors. ExecutorService.C ...
- Java Executor框架使用
Java Executor框架是Jdk1.5之后推出的,是为了更加方便的开发多线程应用而封装的框架: 相比传统的Thread类,Java Executor使用方便,性能更好,更易于管理,而且支持线程池 ...
- JAVA并行框架学习之ForkJoin
当硬件处理能力不能按照摩尔定律垂直发展的时候,选择了水平发展,多核处理器已经广泛应用.未来随着技术的进一步发展,可能出现成百上千个处理核心,但现有的程序运行在多核心处理器上并不能得到较大性能的提升,主 ...
- Executor框架学习笔记
Java中的线程即是工作单元也是执行机制,从JDK 5后,工作单元与执行机制被分离.工作单元包括Runnable和Callable,执行机制由JDK 5中增加的java.util.concurrent ...
- Java集合框架学习(一)List
先附一张Java集合框架图. 从上面的集合框架图可以看到,Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Coll ...
- Java Executor框架
java.util.concurrent 包中包含灵活的线程池实现,但是更重要的是,它包含用于管理实现 Runnable 的任务的执行的整个框架,该框架称为 Executor 框架.该框架基于生产者- ...
- 使用Java Executor框架实现多线程
本文将涵盖两个主题: 通过实现Callable接口创建线程 在Java中使用Executor框架 实现Callable接口 为了创建一段可以在线程中运行的代码,我们创建了一个类,然后实现了Callab ...
- Java集合框架学习
集合框架 集合框架的目标 该框架必须是高性能的.基本集合(动态数组,链表,树,哈希表)的实现必须是高效的. 该框架允许 不同类型的集合,以类似的方式工作,具有高度的互操作性. 对一个集合的扩展和适应必 ...
- Java SSH框架学习(入门)
SSH就是 struts+spring+hibernate 的一个集成框架,是java中一种流行的JAVA WEB 应用程序开源框架.由于我最熟悉的还是ASP.NET的的MVC和Python的Djan ...
随机推荐
- CSS Positioning(定位)
Positioning(定位) CSS定位属性允许你为一个元素定位.它也可以将一个元素放在另一个元素后面,并指定一个元素的内容太大时,应该发生什么. 元素可以使用的顶部,底部,左侧和右侧属性定位.然而 ...
- jQuery实现的分页功能,包括ajax请求,后台数据,有完整demo
一:需求分析 1)需要首页,末页功能 2)有点击查看上一页,下一页功能 3)页码到当前可视页码最后一页刷新页面 二:功能实现思路 也是分为三部分处理 1)点击首页,末页直接显示第一页或者最后一页内容, ...
- 【随记】修复TortoiseGit文件夹和文件状态图标不显示问题
一. 运行环境: 操作系统 Windows 10 64bit TortoiseGit (2.2.0.0) 64bit msysgit(2.9.2.1) 64bit 注意:请确保环境正确,软件的位数相匹 ...
- Action配置
Action是一个逻辑控制器,并不直接对浏览器生成响应,而是返回指定逻辑视图(一个字符串). 不推荐在Action的name属性值中使用点(.)和中划线(-),有可能会引发一些未知异常. 1使用A ...
- Android艺术开发探索第四章——View的工作原理(上)
这章就比较好玩了,主要介绍一下View的工作原理,还有自定义View的实现方法,在Android中,View是一个很重要的角色,简单来说,View是Android中视觉的呈现,在界面上Android提 ...
- chkconfig-增加一个服务设置服务自启动
参考 http://www.cnblogs.com/panjun-Donet/archive/2010/08/10/1796873.html 如何增加一个服务: 1.服务脚本必须存放在/etc/ini ...
- 如何更有效学习php开源项目的源码
一.先把源代码安装起来,结合它的文档和手册,熟悉其功能和它的应用方式. 二.浏览源代码的目录结构,了解各个目录的功能. 三.经过以上两步后相信你对这个开源的产品有了一个初步的了解了,那现在就开始分析它 ...
- PHP 面向对对象基础(接口,类)
介绍PHP面向对象的基础知识 1. 接口的定义interface ,类定义class,类支持abstract和final修饰符,abstract修饰为抽象类,抽象类 不支持直接实例化,final修饰的 ...
- 移动端下拉刷新、加载更多插件dropload.js(基于jQuery/Zepto)
移动端下拉刷新.加载更多插件dropload.js(基于jQuery/Zepto) 原文:http://www.grycheng.com/?p=1869 废话不多说,先让大家看一下案例效果: DEMO ...
- 关于 Log4Net
Log4Net是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件.数据库.EventLog等),日志就是程序的黑匣子,可以通过日志查看系统的运行过程,从而发现系统的问题.日志的作用:将运 ...