Java并发编程实践 目录

并发编程 01—— ThreadLocal

并发编程 02—— ConcurrentHashMap

并发编程 03—— 阻塞队列和生产者-消费者模式

并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier

并发编程 05—— Callable和Future

并发编程 06—— CompletionService : Executor 和 BlockingQueue

并发编程 07—— 任务取消

并发编程 08—— 任务取消 之 中断

并发编程 09—— 任务取消 之 停止基于线程的服务

并发编程 10—— 任务取消 之 关闭 ExecutorService

并发编程 11—— 任务取消 之 “毒丸”对象

并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性

并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略

并发编程 14—— 线程池 之 整体架构

并发编程 15—— 线程池 之 原理一

并发编程 16—— 线程池 之 原理二

并发编程 17—— Lock

并发编程 18—— 使用内置条件队列实现简单的有界缓存

并发编程 19—— 显式的Conditon 对象

并发编程 20—— AbstractQueuedSynchronizer 深入分析

并发编程 21—— 原子变量和非阻塞同步机制

 
 
概述
 

第1 部分 配置ThreadPoolExecutor

1.1 创建

ThreadPoolExecutor为一些Executor提供了基本的实现,比如,newCachedThreadPool,newFixedThreadPool等等。ThreadPoolExecutor允许各种定制

它的构造函数如下:

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}

最常用的newCachedThreadPool。

1.2 管理队列任务

据线程池的大小来选择合适的队列有利于充分利用资源和防止耗尽资源。

基本的排队方法有3种:

  • 无界队列
  • 有界队列
  • 同步移交
对于Executor,newCachedThreadPool工厂方法是一种很好的默认选择,它能提供比固定大小的线程池更好的排队性能。
 

1.3 饱和策略

我们在ThreadPoolExecutor的构造函数中看到了最后一个参数。  RejectedExecutionHandler handler。这个就是饱和策略。

JDK提供了几种不同的实现:

  • DiscardOldestPolicy
  • AbortPolicy
  • CallerRunsPolicy
  • discardPolicy

AbortPolicy是默认的饱和策略,就是中止任务,该策略将抛出RejectedExecutionException。调用者可以捕获这个异常然后去编写代码处理异常。

当新提交的任务无法保存到队列中等待执行时,DiscardPolicy会稍稍的抛弃该任务,DiscardOldestPolicy则会抛弃最旧的(下一个将被执行的任务),然后尝试重新提交新的任务。如果工作队列是那个优先级队列时,搭配DiscardOldestPolicy饱和策略会导致优先级最高的那个任务被抛弃,所以两者不要组合使用。

CallerRunsPolicy是“调用者运行”策略,实现了一种调节机制 。它不会抛弃任务,也不会抛出异常。 而是将任务回退到调用者。它不会在线程池中执行任务,而是在一个调用了Executor的线程中执行该任务。

 /**
* 调用者运行的饱和策略
* @ClassName: ThreadDeadlock2
* TODO
* @author xingle
* @date 2014-11-20 下午4:18:11
*/
public class ThreadDeadlock2 {
ExecutorService exec = new ThreadPoolExecutor(0, 2, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),new ThreadPoolExecutor.CallerRunsPolicy()); private void putrunnable() {
for (int i = 0; i < 4; i++) {
exec.submit(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
while (true) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
}
public static void main(String[] args) {
new ThreadDeadlock2().putrunnable();
}
}

执行结果:

当工作队列被填满之后,没有预定义的饱和策略来阻塞execute。通过使用 Semaphore (信号量)来限制任务的到达率,就可以实现这个功能。在下面的BoundedExecutor 中给出了这种方法,该方法使用了一个无界队列,并设置信号量的上界设置为线程池的大小加上可排队任务的数量,这是因为信号量需要控制正在执行的和正在等待执行的任务数量。

 /**
* 8.4 使用Semaphore来控制任务的提交速率
* @ClassName: BoundedExecutor
* TODO
* @author xingle
* @date 2014-11-20 下午2:46:19
*/
public class BoundedExecutor {
private final Executor exec;
private final Semaphore semaphore;
int bound; public BoundedExecutor(Executor exec,int bound){
this.exec = exec;
this.semaphore = new Semaphore(bound);
this.bound = bound;
} public void submitTask(final Runnable command) throws InterruptedException{
//通过 acquire() 获取一个许可
semaphore.acquire();
System.out.println("----------当前可用的信号量个数:"+semaphore.availablePermits());
try {
exec.execute(new Runnable() { @Override
public void run() {
try {
System.out.println("线程" + Thread.currentThread().getName() +"进入,当前已有" + (bound-semaphore.availablePermits()) + "个并发");
command.run();
} finally {
//release() 释放一个许可
semaphore.release();
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (bound-semaphore.availablePermits()) + "个并发");
}
}
});
} catch (RejectedExecutionException e) {
semaphore.release();
}
}
}

测试程序:

 public class BoundedExecutor_main {
public static void main(String[] args) throws InterruptedException{
ExecutorService exec = Executors.newCachedThreadPool();
BoundedExecutor e = new BoundedExecutor(exec, 3); for(int i = 0;i<5;i++){
final int c = i;
e.submitTask(new Runnable() { @Override
public void run() {
System.out.println("执行任务:" +c);
}
});
}
}
}

执行结果:


参考:
1.《java 并发编程》 8.2-8.3

并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略的更多相关文章

  1. JUC 并发编程--08,线程池,三大方法,七大参数,4种拒绝策略,代码演示

    三大方法: //线程池核心线程数为n, 最大线程数为 n ExecutorService fixedThreadPool = Executors.newFixedThreadPool(n); 源码: ...

  2. 13、Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  3. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  4. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  5. Java并发编程:线程池的使用(转载)

    转载自:https://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  6. Java并发编程:线程池的使用(转载)

    文章出处:http://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  7. [转]Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  8. 【转】Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  9. (转)Java并发编程:线程池的使用

    背景:线程池在面试时候经常遇到,反复出现的问题就是理解不深入,不能做到游刃有余.所以这篇博客是要深入总结线程池的使用. ThreadPoolExecutor的继承关系 线程池的原理 1.线程池状态(4 ...

随机推荐

  1. (转载)throw和throws的区别

    1.throw:(针对对象的做法)抛出一个异常,可以是系统定义的,也可以是自己定义的.下面举两个例子:抛出Java中的一个系统异常:public class One {public void yich ...

  2. 导入charts开源库到工程里面

    http://blog.csdn.net/zww1984774346/article/details/50608338 http://blog.csdn.net/zww1984774346/artic ...

  3. WEB压力测试工具Pylot试用

    Pylot介绍 转载自[http://www.freehao123.com/pylot-web/] 为了能够准确地评估网站服务器对网络流量的承受能力,我们一般会采取模拟网站用户访问,通过不断地增加并发 ...

  4. C++函数模板template

    一.  问题: 强类型语言要求我们为所有希望比较的类型都实现一个实例 int min(int a, int b) { return a < b ? a : b; } double min(dou ...

  5. C# 类的属性

    属性是一个方法或者一对方法.客户端看来是一个字段. 定义属性 public int StudyHours{ //啥不写,默认有get;set; 和后备字段studyHours是private的 get ...

  6. SpringMvc处理JSON

    步骤如下: 1.加入jar包 2.编写目标方法,使其返回JSON对应的对象或集合 3.在方法上添加@ResponseBody注解 DispatcheServlet默认装配RequestMappingH ...

  7. Java 之 List<T> 接口的实现:LinkedList

    Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMap 隶属于队列Lis ...

  8. 【实践】纯jquery实现图片滑动无缝轮播,带左右按钮及控制按钮

    在此随笔之前,博主已经做过一次图片滑动轮播,如过你也有看过就会知道里面的效果在自动轮播的时候有一个不太美观的效果,就是当最后一张图片滑动切换到第一张图片的时候会看到一个快速向左滑动的效果,这是很不美观 ...

  9. [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑

    构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...

  10. 在学Go语言

    首发:个人博客,更新&纠错&回复 开始学点儿Go语言,这语言据说在国内比在国外火,社区上褒贬不一,不过“小马过河”嘛,总要先自己试试再来下结论. 环境准备: 1.在Golang中国下载 ...