ExecutorService 必须通过Executors工厂方法或显式配置ThreadPoolExecutor创建,因手动new易触发OOM或任务堆积,根本原因是默认无界队列和AbortPolicy拒绝策略导致;实操需明确队列容量、拒绝策略、线程命名及业务前缀,并在Spring中用@Bean声明配合@PreDestroy。
为什么
不能直接用
手动构造
手册里反复强调“线程池必须通过
工厂方法创建”,但实际落地时很多人图省事直接 new,结果在线上压测或流量突增时频繁触发 OOM 或任务堆积。根本原因不是语法错,而是默认参数陷阱:
底层用的是无界
,任务持续提交却消费不及时,队列无限膨胀;而手动 new
时若忽略
,默认的
会直接抛
,业务没兜底就挂了。
实操建议:
强制使用
—— 明确队列容量、拒绝策略、线程命名
所有线程池变量名带业务前缀,如
,禁止泛用
在 Spring 环境中统一用
声明,配合
调用
,避免应用停机时线程残留
和
到底该选哪个
不是“新代码一律用
”,也不是“老代码全留着
”。关键看是否需要可中断、超时获取、公平锁或多个条件变量。日常临界资源保护(比如缓存更新、计数器累加),
更轻量、JVM 优化成熟、不易漏写释放逻辑;而涉及复杂协作(如生产者消费者需分别等待不同条件),
的
才能解耦。
常见错误现象:
立即学习
“
Java免费学习笔记(深入)
”;
用
却忘记在
块调用
,导致死锁
在持有
时调用外部服务(如 HTTP 请求),阻塞整个锁粒度,吞吐骤降
误以为
性能一定优于
—— 在无竞争场景下,后者通常更快
为什么
不清理就会内存泄漏
根本不在“线程没销毁”,而在
的 key 是弱引用,value 是强引用。当
变量被回收后,key 变为
,但 value 仍挂在 map 里,且该 map 隶属于线程对象,只要线程(尤其是线程池里的常驻线程)不死,value 就一直占着堆内存。线上最典型的表现是:服务运行几天后 Full GC 频繁,dump 发现大量业务对象无法回收。
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
实操建议:
所有
必须配对调用
,尤其在
中,不能只依赖
禁止在工具类里定义静态
存储用户上下文,应改用方法参数透传或
(仅限父子线程传递)
Spring 环境下优先用
,它内部已封装了
逻辑
CompletableFuture 异步链中异常到底怎么捕获
用
或
处理结果,但上游抛了异常,下游根本收不到——因为异常不会穿透到这些方法,而是静默吞掉,最终整个链在某个环节卡住或返回 null。真正起作用的是
、
或
,但三者语义不同:前者只处理异常,后两者都执行但
允许你返回新值,
只做副作用(如打日志、发告警)。
容易踩的坑:
在
返回的新
上漏加异常处理器,导致嵌套异常丢失
用
阻塞获取结果,却没包 try-catch,把
直接抛给容器(如 Tomcat),触发 500
多个异步分支用
汇聚,但没逐个检查每个 future 的
,误判整体成功
复杂点在于:异常类型可能被包装多层,
得连剥两层才能拿到原始业务异常。这点很容易被忽略,结果告警里全是
,看不出真实问题。
ExecutorServicenew ThreadPoolExecutor(...)ExecutorsExecutors.newFixedThreadPool()LinkedBlockingQueueThreadPoolExecutorRejectedExecutionHandlerAbortPolicyRejectedExecutionExceptionnew ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit, new ArrayBlockingQueue(queueCapacity), r -> new Thread(r, "biz-task-" + counter.getAndIncrement()), new ThreadPoolExecutor.CallerRunsPolicy())orderNotifyExecutorexecutor@Bean@PreDestroyshutdown()synchronizedReentrantLockReentrantLocksynchronizedsynchronizedReentrantLocknewCondition()ReentrantLockfinallyunlock()synchronizedReentrantLocksynchronizedThreadLocalThreadLocalMapThreadLocalnullThreadLocalremove()try-finallyset(null)ThreadLocalInheritableThreadLocalRequestContextHolderremove()thenApplythenAcceptexceptionally()handle()whenComplete()handle()whenComplete()thenComposeCompletableFuturejoin()CompletionExceptionallOf()isCompletedExceptionally()getCause()CompletionException