读Java Concurrency in Practice. 第六章.
这一章开讲任务执行。绝大多数并发程序的工作都可以分解为抽象的、互不相关的工作单元,称之为任务(Task)。
使用java线程来执行任务
以web服务器的实现举例, 此时将用户的一次连接,当做一个独立的任务。
- 单线程顺序执行所有任务。
ServerSocket socket = new ServerSocket(80);
while(true) {
Socket connection = socket.accept();
handleRequest(connection);
}
这是最简单的方式,但效率也是最低的。通常在处理单用户的批量任务的时候,才适用。
- 为每一个任务启动一个线程来执行。
ServerSocket socket = new ServerSocket(80);
while(true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
}
new Thread(task).start();
}
这种方式的线程数没有限制,没有限制的线程数有如下几个缺点。a.每一个任务都要创建和销毁线程,带来额外开销;b.当线程数过多时,会占用过多的内存,会导致CPU大量的上下文切换;c.当线程数超过系统限制时,会导致系>统崩溃,通常的结果是OutOfMemoryError。
java的Executor Framework
Executor Framework提供了标准的方式,将任务的描述提交和任务的执行解耦。在同样的任务描述和提交的方式下,通过采用不同的executor实现类,可以实现不同的执行策略,单线程顺序执行、线程池执行等等。 Executor可以>方便用来实现生产者消费者模式,其中,提交任务的线程可以看做是生产者(生产需要被执行的任务),而执行任务的线程则可以看做是消费者。
- 使用Executor实现web服务器。
//不同的Executor,可以实现不同的执行策略,但任务提交方式是相同的。
Executor exec = ...;
ServerSocket socket = new ServerSocket(80);
while(true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
}
exec.execute(task);
}
什么是执行策略。
- 任务会在哪个线程中被执行?
- 任务会按照什么顺序被执行?FIFO,LIFO,按照优先级?
- 多少个任务被同时执行?
- 允许多少个任务缓存在队列中等待被执行?
- 如果系统负载过重,哪些任务应该被放弃执行,又应该怎样通知应用程序?
- 在执行任务之前和任务执行之后,应该做什么样的操作?
需要管理Executor的生命周期怎么办, 比如想要关闭Executor?答:使用ExecutorService。
执行调度任务,可以使用ScheduledThreadPoolExecutor。与Timer相比,它更优秀。比如a.ScheduledThreadPoolExecutor可以使用多个线程执行任务;b.可以更好地处理执行任务中遇到异常的情况。
需要任务的执行结果怎么办?使用Callable和Future。
提交了一系列的任务,希望在这些任务有执行结果的时候就立刻获取结果?用Future的get方法可以做到,但是使用ExecutorCompletionService可以做得更好, ExecutorCompletionService。ExecutorCompletionService维护一>个BlockingQueue用来保存已经执行完成的任务,并通过实现FutureTask的子类,在任务结束时将任务加入到该队列中。这样一来,又是一个生产者消费者模型,执行任务的ExecutorCompletionService可以看做是生产者,而处理已经完成任务的线程可以看做是消费者。
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
- 需要批量提交任务,并获取这些任务的执行结果?使用ExecutorService接口的invokeAll方法, 但需要注意的是, 在AbstractExecutorService的实现中,这个方法忽略了任务执行过程中抛出的异常。
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (Future<T> f : futures) {
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future<T> f : futures)
f.cancel(true);
}
}
invokeAll方法还有一个指定超时时间的版本,其实现方式是通过在执行过程中不断减时间。
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null || unit == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
long lastTime = System.nanoTime();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
Iterator<Future<T>> it = futures.iterator();
while (it.hasNext()) {
execute((Runnable)(it.next()));
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
if (nanos <= 0)
return futures;
}
for (Future<T> f : futures) {
if (!f.isDone()) {
if (nanos <= 0)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future<T> f : futures)
f.cancel(true);
}
}
- 需要批量提交任务,并且只要这些任务中有一个执行完成就获取结果?使用ExecutorService接口的invokeAny方法, 事实上,在AbstractExecutorService的实现中,invokeAny就是使用ExecutorCompleteService实现的。
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
List<Future<T>> futures= new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
long lastTime = timed ? System.nanoTime() : 0;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
else
f = ecs.take();
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (Future<T> f : futures)
f.cancel(true);
}
}
读Java Concurrency in Practice. 第六章.的更多相关文章
- Java Concurrency in Practice 读书笔记 第十章
粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...
- Java Concurrency in Practice 读书笔记 第二章
第二章的思维导图(代码迟点补上):
- 初读"Thinking in Java"读书笔记之第六章 --- 访问权限控制
包:库单元 包内包含有一组类,他们在单一的名字空间下被组织在一起. 通过import ***.***.*可以将某个包下的所有类导入到当前文件中. 每个Java源文件最多只能有一个public类,且名称 ...
- Java Concurrency In Practice
线程安全 定义 A class is thread-safe if it behaves correctly when accessed from multiple threads, regardle ...
- java并发编程实战(java concurrency in practice)
第一章 线程共享进程范围内的资源,但每个线程都有各自的程序计数器.栈以及局部变量等. 多个线程可以同时调度到多个CPU上运行. 线程的优势? 在服务应用程序中,可以提升资源利用率以及系统吞吐率 ...
- Java Concurrency In Practice -Chapter 2 Thread Safety
Writing thread-safe code is managing access to state and in particular to shared, mutable state. Obj ...
- Java Concurrency in Practice——读书笔记
Thread Safety线程安全 线程安全编码的核心,就是管理对状态(state)的访问,尤其是对(共享shared.可变mutable)状态的访问. shared:指可以被多个线程访问的变量 mu ...
- “全栈2019”Java多线程第三十六章:如何设置线程的等待截止时间
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 下一章 "全栈2019"J ...
- Java Concurrency In Practice - Chapter 1 Introduction
1.1. A (Very) Brief History of Concurrency motivating factors for multiple programs to execute simul ...
随机推荐
- 使用HTML5的File实现base64和图片的互转
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 提高D3js力导向图加载速度(转)
过去一段时间曾两次使用了 D3 力导向图来描绘族群关系. http://bl.ocks.org/mbostock/1062288 第一次用的时候不求甚解,交差了事.当时点也不多,很顺利完成了任务.这一 ...
- 【高德地图API】如何设置Marker的offset?
一些朋友在往地图上添加标注的时候,往往会发现,图片的尖尖角对不上具体的点.比如,我要在上海东方明珠上扎一个点. 首先,我使用取点工具http://lbs.amap.com/console/show/p ...
- Activity后台运行一段时间回来crash问题的分析与解决
最近做项目的时候碰到一个棘手的问题,花了不少时间才找到原因并解决.特此记录这个被我踩过的坑,希望其他朋友遇到此问题不要调到这坑里去了. 问题描述: 1.背景:我的app中某个界面的Activity是继 ...
- android studio 乱码
1. 设置 file- setting -file encodeing- 设置utf-8 2 . build.gradle 添加 tasks.withType(JavaCompile) { opti ...
- Maven 简单配置gpg
1. 下载maven到指定目录,指定对应的gpg的执行命令所需要的属性.这里比如下载解压后的maven目录是: C:\maven-apache-3.3.2 ,那么配置文件目录是: C:\maven-a ...
- SQLServer公历转农历函数(1900年-2049年)
ALTER FUNCTION [dbo].[f_SysGetLunar]( @solarDay DATETIME) RETURNS varchar(20 ...
- Oracle 11g导入导出命令
首先需要进入系统的cmd: 执行导出命令,效果如下 expdp hisjk/hisjk@orcl directory=DATA_PUMP_DIR dumpfile=hisjk.dmp SCHEMAS ...
- JavaScript 调试小技巧
'debugger;' 除了console.log,debugger就是另一个我很喜欢的快速调试的工具,将debugger加入代码之后,Chrome会自动在插入它的地方停止,很像C或者Java里面打断 ...
- android:style.xml
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2006 The Andr ...