-
2021-02-25 16:54:18
定位代码
问题原因分析
这点代码是核心查询方法的一部分,负责控制查询用户信息的缓存处理,当有线程执行进行缓存处理时防止同一时间进行DB查询进行分布式锁lock,保证同一时间只有一个线程进行数据库查询,其他未获取锁的线程进行等待,异步获取用户缓存信息,起到防止缓存穿透的目的。
但是这里没有统一使用线程池进行异步线程的调度和使用,导致线程滥用无法收到统一管理和调度,产生OOM隐患。
问题原因总结
-
1、严格参照编码规范统一使用线程池来进行线程调度和使用,避免对线程使用滥用导致失控产生OOM问题
-
2、由于线上都是虚拟机,OOM后可能也会导致虚拟机无法访问,J-ONE无法操作,Logbook日志无法查看,只能找SA进行宿主机重启恢复
-
3、线上虚拟机配置一般为4U 8G,建议配置可以双实例,单实例JVM 2G,不建议4G是因为还有系统应用占用内存,一般2G够用了
-
4、高版本JDK可以根据业务情况观察GC,调整GC回收器或一些配置参数来进行优化
-
5、线程池根据虚拟机4U单实例或双实例进行配置core,max,queue数量
-
6、吃配置的只能加机器或者关注机器性能,关注机器性能指标,不行就更换
更多相关内容 -
-
springboot中@Async默认线程池导致OOM问题
2020-08-19 03:16:34主要介绍了springboot中@Async默认线程池导致OOM问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
Java线程池中的线程发生OOM会如何?
2021-05-19 08:52:43线程池中如果发生OOM后会如何? 线程池ThreadPoolExecutor当有线程发生了OOM,线程池会停止工作吗? public static void main(String[] args) { ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, ...环境:JDK1.8
线程池中如果发生OOM后会如何?
线程池ThreadPoolExecutor当有线程发生了OOM,线程池会停止工作吗?
public static void main(String[] args) { ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2)) ; pool.execute(() -> { int i = 0 ; for (;;) { System.out.println(Thread.currentThread().getName() + ", i = " + (i++) + "," + pool) ; try { TimeUnit.MILLISECONDS.sleep(50) ; } catch (InterruptedException e) { e.printStackTrace(); } } }); pool.execute(() -> { int j = 0 ; for (;;) { System.out.println(Thread.currentThread().getName() + ", j = " + (j++) + "," + pool) ; try { TimeUnit.MILLISECONDS.sleep(50) ; } catch (InterruptedException e) { e.printStackTrace(); } } }); pool.execute(() -> { int k = 0 ; List<byte[]> datas = new ArrayList<>() ; for (;;) { System.out.println(Thread.currentThread().getName() + ", k = " + (k++) + "," + pool) ; byte[] buf = new byte[1024 * 100] ; datas.add(buf) ; try { TimeUnit.MILLISECONDS.sleep(20) ; } catch (InterruptedException e) { e.printStackTrace(); } } }); }
调整JVM运行内存
-Xms10m -Xmx10m
执行结果:
一开始3个线程交替执行,当其中一个线程发生OOM后,线程池中除了发生OOM的线程池不再继续工作外,其它的线程都继续工作。
自定义线程异常处理
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadFactory() { private final ThreadGroup group = new ThreadGroup("Pack-Group"); private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix = "pool-custom-thread-"; @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("自定义线程异常处理:" + t.getName()); e.printStackTrace(); }}); return t; } });
线程池的拒绝策略
代码:
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.AbortPolicy()) ; for (int i = 0; i < 6; i++) { pool.execute(() -> { System.out.println(Thread.currentThread().getName() + ", 进入执行") ; try { TimeUnit.SECONDS.sleep(2) ; } catch (InterruptedException e) { e.printStackTrace(); } }); } System.out.println("ActiveCount: " + pool.getActiveCount()) ; System.out.println("PoolSize: " + pool.getPoolSize()) ; System.out.println("TaskCount: " + pool.getTaskCount()) ;
1、AbortPolicy策略
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.AbortPolicy()) ;
当任务数 > 线程数 + 队列大小。超过的任务直接拒绝并且抛出异常。程序不会继续往下执行。
2、CallerRunsPolicy策略
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.CallerRunsPolicy()) ;
超过的任务会由调用者线程(执行execute方法所在的线程)执行任务。
3、DiscardOldestPolicy策略
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.DiscardOldestPolicy()) ; for (int i = 0; i < 5; i++) { pool.execute(() -> { System.out.println(Thread.currentThread().getName() + ", 进入执行") ; try { TimeUnit.SECONDS.sleep(2) ; } catch (InterruptedException e) { e.printStackTrace(); } }); } System.out.println("ActiveCount: " + pool.getActiveCount()) ; System.out.println("PoolSize: " + pool.getPoolSize()) ; System.out.println("TaskCount: " + pool.getTaskCount()) ; pool.execute(() -> { System.out.println(Thread.currentThread().getName() + ", 我是新入任务") ; });
执行结果:
该策略会把任务队列中的列头删除,然后将自己放入队列(列尾)
4、DiscardPolicy策略
ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.DiscardPolicy()) ; for (int i = 0; i < 7; i++) { pool.execute(() -> { System.out.println(Thread.currentThread().getName() + ", 进入执行") ; try { TimeUnit.SECONDS.sleep(2) ; } catch (InterruptedException e) { e.printStackTrace(); } }); } System.out.println("ActiveCount: " + pool.getActiveCount()) ; System.out.println("PoolSize: " + pool.getPoolSize()) ; System.out.println("TaskCount: " + pool.getTaskCount()) ; TimeUnit.SECONDS.sleep(5) ; pool.execute(() -> { System.out.println(Thread.currentThread().getName() + ", 新任务执行") ; });
执行结果:
该策略什么也不做,线程池能够正常继续执行下去。
自定义线程池
自定义线程池监控线程执行耗时时间
public class CustomThreadPool extends ThreadPoolExecutor { public CustomThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); if (r instanceof Task) { ((Task) r).setStart(System.currentTimeMillis()) ; System.out.println(t.getName() + ", 开始执行") ; } } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (r instanceof Task) { ((Task) r).times(); } } public void execute(Task command) { super.execute(command); } public static class Task implements Runnable { private long start ; private Callback callback ; public Task(Callback callback) { this.callback = callback ; } @Override public void run() { if (this.callback != null) { this.callback.callback(); } } public void times() { System.out.println(Thread.currentThread().getName() + " 执行耗时:" + (System.currentTimeMillis() - start) + "ms") ; } public void setStart(long start) { this.start = start; } } public static interface Callback { void callback() ; } }
重写beforeExecute,afterExecute父类的这两个方法,线程执行前和执行后。
CustomThreadPool pool = new CustomThreadPool(3, 3, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2)) ; pool.execute(new Task(() -> { try { TimeUnit.SECONDS.sleep(1) ; } catch (InterruptedException e) { e.printStackTrace(); } })) ; pool.execute(new Task(() -> { try { TimeUnit.SECONDS.sleep(3) ; } catch (InterruptedException e) { e.printStackTrace(); } })) ; pool.execute(new Task(() -> { try { TimeUnit.SECONDS.sleep(2) ; } catch (InterruptedException e) { e.printStackTrace(); } })) ;
执行结果:
给个关注谢谢
-
线程池OOM异常
2020-10-23 13:29:03现象 MAC unable to creat new native thread window 测试前 在启动测试类之前先将JVM内存...(-Xms10M Java Heap内存初始化值 -Xmx10M Java Heap内存最大值) Exception in thread “main” java.lang.OutOfMemoryEr现象
MAC
unable to creat new native thread
window
测试前 在启动测试类之前先将JVM内存调整小一点,不然很容易将电脑跑出问题
在idea里:Run -> Edit Configurations VM options修改成-Xms10M -Xmx10M
(-Xms10M Java Heap内存初始化值 -Xmx10M Java Heap内存最大值)
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space。
代码public static void main(String[] args) throws InterruptedException { AtomicInteger i = new AtomicInteger(0); for (; ; ) { Executors.newFixedThreadPool(10).submit(() -> System.out.println(i.getAndIncrement())); Thread.sleep(4); } }
循环创建线程池 而并没有关闭线程池,导致线程池的实例会一直存在
源码
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public LinkedBlockingQueue() { this(Integer.MAX_VALUE); // MAX_VALUE = 0x7fffffff } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
原因分析
Java常见的GC Root
Java 进行GC的时候会从GC root进行可达性判断,常见的GC Root有如下:- 通过System Class Loader或者Boot Class Loader加载的class对象,通过自定义类加载器加载的class不一定是GC Root
- 处于激活状态的线程
- 栈中的对象
- JNI栈中的对象
- JNI中的全局对象
- 正在被用于同步的各种锁对象
- JVM自身持有的对象,比如系统类加载器等。
在调查内存泄漏原因的时候可以根据GC Root来推导
当执行一个Runnable时,会先创建一个ThreadPoolExecutor中的内部类Worker对象,将这个Runnable对象作为Worker对象的一个成员变量
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); } private volatile ThreadFactory threadFactory; public ThreadFactory getThreadFactory() { return threadFactory; }
所以 当线程在执行的时候引用关系如下ThreadPoolExecutor->Worker->thread
一个运行的线程是作为GC ROOT的,不会被GC; 所以要主动shutdownnewSingleThreadExecutor不会有此问题,因为FinalizableDelegatedExecutorService 重写了finalize函数,也就是说这个类会在被GC回收之前,先执行线程池的shutdown方法。
java.util.concurrent.Executors public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } static class FinalizableDelegatedExecutorService extends DelegatedExecutorService { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } protected void finalize() { super.shutdown(); } }
-
springboot-@Async默认线程池导致OOM问题
2020-12-24 11:46:00转springboot-@Async默认线程池导致OOM问题版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。前言:1.最近项目上在测试人员压测过程中发现了OOM问题,项目使用springboot...转
springboot-@Async默认线程池导致OOM问题
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
前言:
1.最近项目上在测试人员压测过程中发现了OOM问题,项目使用springboot搭建项目工程,通过查看日志中包含信息:unable to create new native thread
内存溢出的三种类型:
1.第一种OutOfMemoryError: PermGen space,发生这种问题的原意是程序中使用了大量的jar或class
2.第二种OutOfMemoryError: Java heap space,发生这种问题的原因是java虚拟机创建的对象太多
3.第三种OutOfMemoryError:unable to create new native thread,创建线程数量太多,占用内存过大
初步分析:
1.初步怀疑是线程创建太多导致,使用jstack 线程号 > /tmp/oom.log将应用的线程信息打印出来。查看oom.log,发现大量线程处于Runnable状态,基本可以确认是线程创建太多了。
代码分析:
1.出问题的微服务是日志写库服务,对比日志,锁定在writeLog方法上,wirteLog方法使用spring-@Async注解,写库操作采用的是异步写入方式。
2.之前没有对@Async注解深入研究过,只是知道可以自定义内部线程池,经查看,日志写库服务并未自定义异步配置,使用的是spring-@Async默认异步配置
3.首先简单百度了下,网上提到@Async默认异步配置使用的是SimpleAsyncTaskExecutor,该线程池默认来一个任务创建一个线程,在压测情况下,会有大量写库请求进入日志写库服务,这时就会不断创建大量线程,极有可能压爆服务器内存。
借此机会也学习了下SimpleAsyncTaskExecutor源码,总结如下:
1.SimpleAsyncTaskExecutor提供了限流机制,通过concurrencyLimit属性来控制开关,当concurrencyLimit>=0时开启限流机制,默认关闭限流机制即concurrencyLimit=-1,当关闭情况下,会不断创建新的线程来处理任务,核心代码如下:
public void execute(Runnable task, long startTimeout) {
Assert.notNull(task, "Runnable must not be null");
Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
//判断是否开启限流机制
if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
//执行前置操作,进行限流
this.concurrencyThrottle.beforeAccess();
//执行完线程任务,会执行后置操作concurrencyThrottle.afterAccess(),配合进行限流
doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
}
else {
doExecute(taskToUse);
}
}
2.SimpleAsyncTaskExecutor限流实现
首先任务进来,会循环判断当前执行线程数是否超过concurrencyLimit,如果超了,则当前线程调用wait方法,释放monitor对象锁,进入等待
protected void beforeAccess() {
if (this.concurrencyLimit == NO_CONCURRENCY) {
throw new IllegalStateException(
"Currently no invocations allowed - concurrency limit set to NO_CONCURRENCY");
}
if (this.concurrencyLimit > 0) {
boolean debug = logger.isDebugEnabled();
synchronized (this.monitor) {
boolean interrupted = false;
while (this.concurrencyCount >= this.concurrencyLimit) {
if (interrupted) {
throw new IllegalStateException("Thread was interrupted while waiting for invocation access, " +
"but concurrency limit still does not allow for entering");
}
if (debug) {
logger.debug("Concurrency count " + this.concurrencyCount +
" has reached limit " + this.concurrencyLimit + " - blocking");
}
try {
this.monitor.wait();
}
catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
interrupted = true;
}
}
if (debug) {
logger.debug("Entering throttle at concurrency count " + this.concurrencyCount);
}
this.concurrencyCount++;
}
}
}
2.SimpleAsyncTaskExecutor限流实现:首先任务进来,会循环判断当前执行线程数是否超过concurrencyLimit,如果超了,则当前线程调用wait方法,释放monitor对象锁,进入等待状态。
protected void beforeAccess() {
if (this.concurrencyLimit == NO_CONCURRENCY) {
throw new IllegalStateException(
"Currently no invocations allowed - concurrency limit set to NO_CONCURRENCY");
}
if (this.concurrencyLimit > 0) {
boolean debug = logger.isDebugEnabled();
synchronized (this.monitor) {
boolean interrupted = false;
while (this.concurrencyCount >= this.concurrencyLimit) {
if (interrupted) {
throw new IllegalStateException("Thread was interrupted while waiting for invocation access, " +
"but concurrency limit still does not allow for entering");
}
if (debug) {
logger.debug("Concurrency count " + this.concurrencyCount +
" has reached limit " + this.concurrencyLimit + " - blocking");
}
try {
this.monitor.wait();
}
catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
interrupted = true;
}
}
if (debug) {
logger.debug("Entering throttle at concurrency count " + this.concurrencyCount);
}
this.concurrencyCount++;
}
}
}
线程任务执行完毕后,当前执行线程数会减一,会调用monitor对象的notify方法,唤醒等待状态下的线程,等待状态下的线程会竞争monitor锁,竞争到,会继续执行线程任务。
protected void afterAccess() {
if (this.concurrencyLimit >= 0) {
synchronized (this.monitor) {
this.concurrencyCount--;
if (logger.isDebugEnabled()) {
logger.debug("Returning from throttle at concurrency count " + this.concurrencyCount);
}
this.monitor.notify();
}
}
}
虽然看了源码了解了SimpleAsyncTaskExecutor有限流机制,实践出真知,我们还是测试下:
一、测试未开启限流机制下,我们启动20个线程去调用异步方法,查看Java VisualVM工具如下:
在这里插入图片描述
二、测试开启限流机制,开启限流机制的代码如下:
@Configuration
@EnableAsync
public class AsyncCommonConfig extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
//设置允许同时执行的线程数为10
executor.setConcurrencyLimit(10);
return executor;
}
}
同样,我们启动20个线程去调用异步方法,查看Java VisualVM工具如下:
在这里插入图片描述
通过上面验证可知:
1.开启限流情况下,能有效控制应用线程数
2.虽然可以有效控制线程数,但执行效率会降低,会出现主线程等待,线程竞争的情况。
3.限流机制适用于任务处理比较快的场景,对于应用处理时间比较慢的场景并不适用。==
最终解决办法:
1.自定义线程池,使用LinkedBlockingQueue阻塞队列来限定线程池的上限
2.定义拒绝策略,如果队列满了,则拒绝处理该任务,打印日志,代码如下:
public class AsyncConfig implements AsyncConfigurer{
private Logger logger = LogManager.getLogger();
@Value("${thread.pool.corePoolSize:10}")
private int corePoolSize;
@Value("${thread.pool.maxPoolSize:20}")
private int maxPoolSize;
@Value("${thread.pool.keepAliveSeconds:4}")
private int keepAliveSeconds;
@Value("${thread.pool.queueCapacity:512}")
private int queueCapacity;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setQueueCapacity(queueCapacity);
executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) -> {
logger.warn("当前任务线程池队列已满.");
});
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable ex , Method method , Object... params) {
logger.error("线程池执行任务发生未知异常.", ex);
}
};
}
}
-
JVM heap dump分析,排查Java线程池误用导致OOM
2020-07-26 23:39:06当出现千万量级的push,free的内存从20g一下子打到只剩5g,最后导致OOM,服务直接重启 利用MAT检查内存泄露 heapdump文件生成 在故障定位(尤其是OOM)和性能分析的时候,经常会用到一些文件辅助我们排除代码问题。... -
Java线程池监控应用
2022-02-22 22:01:59线程池是我们平时开发中使用较多的一种组件,其主要监控点在于池中的线程和阻塞队列中的任务情况。 构建一个线程池 先构建一个基本的线程池,并看看有哪些参数我们可以直接获取到 public class ThreadPoolMonitor { ... -
【073期】Spring Boot 项目 @Async 默认线程池导致 OOM 问题如何解决?
2021-08-07 00:55:09>>号外:关注“Java精选”公众号,回复“面试资料”,免费领取资料!“Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!前言:1.最近项目... -
Java 线程池.docx
2020-09-13 16:08:19资源回答:为什么需要线程池?常见的线程池有哪几个种?线程池的核心参数有哪几个?线程池的核心原理?线程池的拒绝策略。属于高频面试题 -
Java线程池中的各个参数如何合理设置
2021-12-02 16:16:26在开发过程中,好多场景要用到线程池。每次都是自己根据业务场景来设置线程池中的各个参数。 这两天又有需求碰到了,索性总结一下方便以后再遇到可以直接看着用。 虽说根据业务场景来设置各个参数的值,但有些万变... -
Java创建线程池
2022-04-24 17:51:34Java创建线程池 线程池:4大方法,7大参数,4种拒绝策略 池化技术:把一些能够复用的东西(比如说数据库连接、线程)放到池中,避免重复创建、销毁的开销,从而极大提高性能。 优点: 降低系统资源消耗,通过... -
java线程池案例
2022-03-03 16:34:02简介 线程Thread是一个重量级资源,线程的创建、启动以及销毁都是...当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用。 一个线程池包括以下四个基 -
线程池不关闭引发的OOM血案
2022-06-09 19:32:03竟然是OOM,Java应用程序已达到其可以启动线程数量的极限了。肯定是有地方创建了太多线程,消耗光了系统的线程数。 Caused by: java.lang.OutOfMemoryError: unable to create new native thread由于线上机器已经... -
java线程池详解
2021-12-01 11:19:401.线程池使用场景? java中经常需要用到多线程来处理一些...java中涉及到线程池的相关类均在jdk1.5开始的java.util.concurrent包中,涉及到的几个核心类及接口包括:Executor、Executors、ExecutorService、ThreadPo -
四种Java线程池用法解析
2020-09-02 14:05:47主要为大家解析四种Java线程池用法,内容详细,分析细致,感兴趣的小伙伴们可以参考一下 -
java线程池详解及五种线程池方法详解
2022-04-04 11:02:07Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThreads),但是便捷不仅隐藏了复杂性,也为我们埋下了潜在的隐患(OOM,线程耗尽)。 Executors创建... -
Java线程池详解
2021-05-11 17:11:57文章目录简介什么是线程池银行营业厅案例执行流程创建方式所有创建方式通过ThreadPoolExecutor创建 简介 什么是线程池 线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。它是将多个线程预先存储在一个... -
图文详解 Java线程池
2021-03-19 11:36:321、线程池的优势 (1)降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗; (2)提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行; (3)方便线程并发... -
Java线程池的使用方法
2021-08-26 21:48:54通俗点讲,当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用。 接下来从总体到细致的方式,来共同探讨线程池。 总体的架构 -
Java线程池Executor详解
2021-12-12 22:12:25我们最常使用的Executors实现创建线程池使用线程主要是用上述类图中提供的类。在上边的类图中,包含了一个Executor框架,它是一个根据一组执行策略的调用调度执行和控制异步任务的框架,目的是提供一种将任务提交与... -
Java线程池的工作原理
2021-08-16 20:57:10线程池是一种池化思想的体现,经常出现在多线程程序中。使用多线程技术,主要几个优势:降低资源的开销、提高系统运行速度、对线程可管理性、提供更加强大的功能。 二、如何使用线程池 1、ThreadPoolExecutor通用... -
Java线程池
2022-03-10 18:20:01线程池 线程池由两个核心数据结构...当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就 -
Java线程池七个参数详解
2022-05-10 20:02:47java多线程开发时,常常用到线程池技术,这篇文章是对创建线程池时的7个参数的详细介绍。 -
java线程池使用最全详解
2021-05-18 15:14:46线程池使用 ...方便线程并发数的管控,线程若是无限制的创建,不仅会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等状况,从而降低系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源 -
JAVA线程池的使用
2022-03-31 20:58:54/* 该方法返回一个固定线程数量的线程池,该线程池池中的线程数量始终不变。 * 当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。 * 若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便... -
从Executors和ThreadPoolExecutor的区别分析到线程池的OOM
2020-09-08 16:52:33很多人都知道阿里的Java开发严令禁止使用Executors的方式来创建线程池,禁止的理由是“为了让开发者更加明确线程池的运行规则,更加了解线程池的底层工作原理,从而避免不规范的使用造成服务器资源耗尽的风险”,本... -
JAVA线程池的正确使用
2021-08-11 20:53:10参考文章:Java并发编程正确打开线程池的方式 1. 概述 线程可认为是操作系统可调度的最小的程序执行序列,一般作为进程的组成部分,同一进程中多个线程可共享该进程的资源(如内存等)。JVM线程跟内核轻量级进程有... -
Java线程池理解
2022-01-24 20:50:48提高响应速度:当任务到达的时候,不用再创建线程,可以由线程池中空闲的线程来执行 提高线程的可管理性:如果线程无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以对线程进行统一的分配,...