Java并发——阿里架构师是如何巧用线程池的!
一、创建线程
1.创建普通对象,只是在JVM的堆里分配一块内存而已
2.创建线程,需要调用操作系统内核的API,然后操作系统需要为线程分配一系列资源,成本很高
- 线程是一个重量级对象,应该避免频繁创建和销毁,采用线程池方案
二、一般的池化资源
// 假设Java线程池采用一般意义上池化资源的设计方法
class ThreadPool {
// 获取空闲线程
Thread acquire() {
}
// 释放线程
void release(Thread t) {
}
}
// 期望的使用
ThreadPool pool;
Thread T1 = pool.acquire();
// 传入Runnable对象
T1.execute(() -> {
// 具体业务逻辑
});
三、生产者-消费者模式
业界线程池的设计,普遍采用生产者-消费者模式,线程池的使用方是生产者,线程池本身是消费者
public class MyThreadPool {
// 工作线程负责消费任务并执行任务
class WorkerThread extends Thread {
@Override
public void run() {
// 循环取任务并执行
while (true) {
Runnable task = null;
try {
task = workQueue.take();
} catch (InterruptedException e) {
}
task.run();
}
}
}
// 利用阻塞队列实现生产者-消费者模式
private BlockingQueue<Runnable> workQueue;
// 内部保存工作线程
List<WorkerThread> threads = new ArrayList<>();
public MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {
this.workQueue = workQueue;
for (int i = 0; i < poolSize; i++) {
WorkerThread work = new WorkerThread();
work.start();
threads.add(work);
}
}
// 提交任务
public void execute(Runnable command) throws InterruptedException {
workQueue.put(command);
}
public static void main(String[] args) throws InterruptedException {
// 创建有界阻塞队列
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
// 创建线程池
MyThreadPool pool = new MyThreadPool(10, workQueue);
// 提交任务
pool.execute(() -> {
System.out.println("hello");
});
}
}
四、Java线程池
Ⅰ. ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
// 让所有线程都支持超时,如果线程池很闲,那么将撤销所有线程
public void allowCoreThreadTimeOut(boolean value)
1.corePoolSize:线程池保有的最小线程数
2.maximumPoolSize:线程池创建的最大线程数
3.keepAliveTime & unit
- 如果一个线程空闲了keepAliveTime & unit,并且线程池的线程数大于corePoolSize,那么这个空闲的线程就要被回收
4.workQueue:工作队列
5.threadFactory:自定义如何创建线程
6.handler
- 线程池中的所有线程都很忙碌,并且工作队列也满了(工作队列是有界队列),此时提交任务,线程池会拒绝接收
- CallerRunsPolicy:提交任务的线程自己去执行该任务
- AbortPolicy:默认的拒绝策略,抛出RejectedExecutionException
- DiscardPolicy:直接丢弃任务,不会抛出任何异常
- DiscardOldestPolicy:丢弃最老的任务,然后把新任务加入到工作队列中
Ⅱ. Executors
1.不建议使用Executors,因为Executors提供的很多默认方法使用的是无界队列LinkedBlockingQueue
2.在高负载的情况下,无界队列容易导致OOM,而OOM会导致所有请求都无法处理
3.因此强烈建议使用有界队列
Ⅲ. 拒绝策略
1.使用有界队列,当任务过多时,线程池会触发拒绝策略
2.线程池默认的拒绝策略会抛出RejectedExecutionException,这是一个运行时异常,开发时很容易忽略
3.如果线程池处理的任务非常重要,可以自定义拒绝策略
Ⅳ. 异常处理
1.使用ThreadPoolExecutor.execute()方法提交任务时,如果任务在执行过程中出现运行时异常
- 会导致执行任务的线程终止,并且无法获得任何通知
2.因此最稳妥的方法还是捕获所有异常并处理
try {
// 业务逻辑
} catch (RuntimeException x) {
// 按需处理
} catch (Throwable x) {
// 按需处理
}
写在最后

Java并发——阿里架构师是如何巧用线程池的!的更多相关文章
- java并发编程(十七)Executor框架和线程池
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...
- Java并发编程原理与实战三十七:线程池的原理与使用
一.简介 线程池在我们的高并发环境下,实际应用是非常多的!!适用频率非常高! 有过使用过Executors框架的朋友,可能不太知道底层的实现,这里就是讲Executors是由ThreadPoolExe ...
- Java并发(基础知识)—— Executor框架及线程池
在Java并发(基础知识)—— 创建.运行以及停止一个线程中讲解了两种创建线程的方式:直接继承Thread类以及实现Runnable接口并赋给Thread,这两种创建线程的方式在线程比较少的时候是没有 ...
- Java并发编程实践读书笔记(5) 线程池的使用
Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...
- 【java并发编程实战】第六章:线程池
1.线程池 众所周知创建大量线程时代价是非常大的: - 线程的生命周期开销非常大:创建需要时间,导致延迟处理请求,jvm需要分配空间. - 资源消耗:线程需要占用空间,如果线程数大于可用的处理器数量, ...
- Java并发编程的艺术笔记(八)——线程池
一.线程池的主要处理流程 ThreadPoolExecutor执行execute方法分下面4种情况. 1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获 ...
- 阿里架构师的这一份Spring boot使用心得:网友看到都收藏了
阿里架构师的这一份Spring boot使用心得: 这一份PDF将从Spring Boot的出现开始讲起,到基本的环境搭建,进而对Spring的IOC及AOP进行详细讲解.以此作为理论基础,接着进行数 ...
- 深入理解Java并发框架AQS系列(一):线程
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
随机推荐
- [miniApp] WeChat user login code
in client/app.js, we put user login logic inside here, so that other module can reuse those code by ...
- 犀牛Phinoceros 如何切换中文语言
Tools-Options-Rhino Options-Appearance,然后改成中文
- Eclipse改动Project的文件夹位置
Eclipse打开时会要求指定一个workspace, 在这个workspace中能够创建多个相关的或无关的Project, 这些Project的文件夹位置信息存储在: <path to wor ...
- 利用FFmpge进行视频压缩(从图像到H264视频流)
对于FFmpeg相信做视频或图像处理这一块的都不会陌生,在网上也能找到非常多相关的代码.但因为版本号不同等原因.往往找到的代码都是须要自行改动才干够用,为此本人希望能尽绵薄之力,将开发包和自行编写的代 ...
- user agent stylesheet 解决方法
写了一个写了一个页面字体一直是加粗.原来是 strong,b{ user agent stylesheet font-weight:bold; } 引起的 解决方法:又一次定义 strong,b{ f ...
- 大话设计模式宏观总结——创建型&结构型&行为型
师傅验收项目的时候.问大话设计模式那三种类型的差别和联系是什么,顿时我傻了眼.由于除了知道这三种类型分别如何称呼以外.从来都没想过为什么这样划分?于是,我便回答:我没想过这个问题.若是从字面上来理解的 ...
- 360p以上
请选择200MB以内,360p以上,时长3秒到300秒的文件.(支持格式:mp4.3gp.avi.mov.m4v.mkv文件)
- 逆向工程之App脱壳
http://www.cnblogs.com/ludashi/p/5725743.html iOS逆向工程之App脱壳 本篇博客以微信为例,给微信脱壳."砸壳"在iOS逆向工程中是 ...
- bzoj1477 && exgcd学习笔记
exgcd 由于忘记了exgcd,这道题就没做出来... exgcd的用处是求ax+by=gcd(a,b)这样方程的解 大概是这个样子的 void ext_gcd(long long a, long ...
- SpringMVC+MyBaties关于上传(跟新)图片的问题
/** * 方法名:uploadPhoto * 描 述:TODO(上传图片) * 作 者:池彦龙 * 时 间:2017/03/30 * 返回类型: * 参 数: * 异 常: */ Controlle ...