Appearance
源码:labs/java/runtime-concurrency/thread-pool-basics/src/AndroidThreadPoolPresets.java
- 原始路径:
labs/java/runtime-concurrency/thread-pool-basics/src/AndroidThreadPoolPresets.java - 类型:
java
java
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Android 侧常见 ThreadPoolExecutor 预设与 Executors 工厂方法对比。
*
* 运行:
* cd labs/java/runtime-concurrency/thread-pool-basics
* javac -d out src/AndroidThreadPoolPresets.java
* java -cp out AndroidThreadPoolPresets
*/
public class AndroidThreadPoolPresets {
public static void main(String[] args) throws Exception {
System.out.println("====== 1. Executors 工厂方法底层参数对比 ======");
printExecutorsFactoryInternals();
System.out.println("\n====== 2. newFixedThreadPool:线程不涨、任务进无界队列 ======");
demoFixedPoolQueueGrowth();
System.out.println("\n====== 3. newCachedThreadPool:不排队、优先扩线程 ======");
demoCachedPoolThreadGrowth();
System.out.println("\n====== 4. Android 推荐:图片压缩池(AbortPolicy,满则拒绝)======");
demoPreset("图片压缩池", createImageCompressPool(), 25, 100);
System.out.println("\n====== 4b. 备选:图片压缩池 + CallerRunsPolicy(仅后台提交路径可用)======");
demoCallerRunsImageCompressPoolNote();
System.out.println("\n====== 5. Android 推荐:IO 池(阻塞型任务,队列略大)======");
demoPreset("IO 池", createIoPool(), 5, 50);
System.out.println("\n====== 6. Android 推荐:串行日志池(单线程顺序写)======");
demoPreset("串行日志池", createSerialLogPool(), 4, 30);
System.out.println("\n====== 7. Android 推荐:实时预览池(DiscardOldest,新任务优先)======");
demoPreset("实时预览池", createPreviewPool(), 6, 40);
}
// -------------------------------------------------------------------------
// Executors 工厂方法:只看参数就能理解风险
// -------------------------------------------------------------------------
static void printExecutorsFactoryInternals() throws InterruptedException {
ThreadPoolExecutor fixed = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
ThreadPoolExecutor cached = (ThreadPoolExecutor) Executors.newCachedThreadPool();
System.out.println("[newFixedThreadPool(2)]");
printPoolSpec(fixed, "固定 n 线程 + 默认 LinkedBlockingQueue(容量约 21 亿)→ 高峰任务堆队列,易 OOM");
System.out.println("[newCachedThreadPool()]");
printPoolSpec(cached, "core=0, max=Integer.MAX_VALUE + SynchronousQueue → 高峰疯狂建线程,易 OOM");
shutdownQuietly(fixed);
shutdownQuietly(cached);
}
static void demoFixedPoolQueueGrowth() throws InterruptedException {
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
submitSlowTasks(pool, 5, "fixed-task");
System.out.println("提交 5 个慢任务后 | 活跃线程: " + pool.getActiveCount()
+ " | 队列堆积: " + pool.getQueue().size()
+ " (线程数仍为 2,多出来的全在队列里等)");
shutdownQuietly(pool);
}
static void demoCachedPoolThreadGrowth() throws InterruptedException {
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
submitSlowTasks(pool, 5, "cached-task");
System.out.println("提交 5 个慢任务后 | 池大小: " + pool.getPoolSize()
+ " | 活跃线程: " + pool.getActiveCount()
+ " | 队列堆积: " + pool.getQueue().size()
+ " (SynchronousQueue 不排队,倾向于直接扩线程)");
shutdownQuietly(pool);
}
// -------------------------------------------------------------------------
// Android 工程里更常见的显式 ThreadPoolExecutor 预设
// -------------------------------------------------------------------------
/**
* 图片压缩 / 解码(默认推荐):CPU + 少量 IO,保守线程数 + 小队列。
* 池满时 {@link ThreadPoolExecutor.AbortPolicy} 抛
* {@link RejectedExecutionException},
* 上层应 try-catch 后提示用户、排队重试或降级——避免在主线程同步执行重活。
*/
static ThreadPoolExecutor createImageCompressPool() {
return newImageCompressPool(new ThreadPoolExecutor.AbortPolicy());
}
/**
* 图片压缩池的 CallerRuns 备选方案。
* <p>
* <b>仅当能保证所有 {@code execute/submit} 都来自后台线程时</b>才可使用:
* 池满时由提交线程同步执行任务,形成自然背压。
* 若从主线程提交,触发后会在 UI 线程跑压缩逻辑,极易 ANR。
*/
static ThreadPoolExecutor createImageCompressPoolWithCallerRuns() {
return newImageCompressPool(new ThreadPoolExecutor.CallerRunsPolicy());
}
static ThreadPoolExecutor newImageCompressPool(RejectedExecutionHandler handler) {
int cores = Runtime.getRuntime().availableProcessors();
int core = Math.max(2, cores / 2);
int max = Math.max(core, cores);
return new ThreadPoolExecutor(
core,
max,
30L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(8),
namedFactory("img-compress"),
handler);
}
/**
* 本地 DB / 文件 / 网络回调后的磁盘写入:线程可略多,队列中等,失败要可见。
*/
static ThreadPoolExecutor createIoPool() {
int cores = Runtime.getRuntime().availableProcessors();
int core = Math.max(4, cores * 2);
int max = core + 1;
return new ThreadPoolExecutor(
core,
max,
60L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(64),
namedFactory("io-worker"),
new ThreadPoolExecutor.AbortPolicy());
}
/**
* 异步日志 / 埋点落盘:单线程保证顺序,队列满则丢低价值日志。
*/
static ThreadPoolExecutor createSerialLogPool() {
return new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(200),
namedFactory("log-writer"),
new ThreadPoolExecutor.DiscardPolicy());
}
/**
* 缩略图 / 列表项预览:旧帧可丢,新提交更重要。
*/
static ThreadPoolExecutor createPreviewPool() {
return new ThreadPoolExecutor(
2,
4,
10L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4),
namedFactory("preview"),
new ThreadPoolExecutor.DiscardOldestPolicy());
}
// -------------------------------------------------------------------------
// 演示辅助
// -------------------------------------------------------------------------
static void demoCallerRunsImageCompressPoolNote() throws InterruptedException {
ThreadPoolExecutor pool = createImageCompressPoolWithCallerRuns();
System.out.println("[图片压缩池-CallerRuns 备选] core=" + pool.getCorePoolSize()
+ ", max=" + pool.getMaximumPoolSize()
+ ", policy=CallerRunsPolicy");
System.out.println(" → 仅后台提交路径可用;池满时由提交线程同步执行,主线程提交有 ANR 风险。");
System.out.println(" → 默认推荐 createImageCompressPool()(AbortPolicy),失败由业务层重试/降级。");
shutdownQuietly(pool);
}
static void demoPreset(String label, ThreadPoolExecutor pool, int taskCount, long workMs)
throws InterruptedException {
System.out.println("[" + label + "] core=" + pool.getCorePoolSize()
+ ", max=" + pool.getMaximumPoolSize()
+ ", queue=" + pool.getQueue().getClass().getSimpleName()
+ ", policy=" + pool.getRejectedExecutionHandler().getClass().getSimpleName());
AtomicInteger rejected = new AtomicInteger();
for (int i = 1; i <= taskCount; i++) {
final int taskId = i;
try {
pool.execute(() -> {
try {
Thread.sleep(workMs);
System.out.println(" " + label + " | 任务 " + taskId
+ " 完成于 [" + Thread.currentThread().getName() + "]");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
} catch (RejectedExecutionException e) {
rejected.incrementAndGet();
System.out.println(" " + label + " | 任务 " + taskId + " 被拒绝 ("
+ pool.getRejectedExecutionHandler().getClass().getSimpleName() + ")");
}
}
Thread.sleep(150);
System.out.println(" 提交后快照 | 活跃: " + pool.getActiveCount()
+ " | 队列: " + pool.getQueue().size()
+ " | 池大小: " + pool.getPoolSize()
+ " | 拒绝次数: " + rejected.get());
shutdownQuietly(pool);
}
static void submitSlowTasks(ThreadPoolExecutor pool, int count, String prefix)
throws InterruptedException {
for (int i = 1; i <= count; i++) {
final int taskId = i;
pool.execute(() -> {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(" " + prefix + "-" + taskId + " 完成于 ["
+ Thread.currentThread().getName() + "]");
});
}
Thread.sleep(50);
}
static ThreadFactory namedFactory(String prefix) {
AtomicInteger seq = new AtomicInteger(1);
return r -> {
Thread t = new Thread(r, prefix + "-" + seq.getAndIncrement());
t.setDaemon(true);
return t;
};
}
static void printPoolSpec(ThreadPoolExecutor pool, String risk) {
String queueType = pool.getQueue().getClass().getSimpleName();
String queueDetail = queueType;
if (pool.getQueue() instanceof LinkedBlockingQueue) {
queueDetail += "(默认近无界)";
} else if (pool.getQueue() instanceof SynchronousQueue) {
queueDetail += "(零容量,不排队)";
} else if (pool.getQueue() instanceof ArrayBlockingQueue) {
queueDetail += "(有界)";
}
System.out.println(" core=" + pool.getCorePoolSize()
+ ", max=" + pool.getMaximumPoolSize()
+ ", queue=" + queueDetail
+ ", keepAlive=" + pool.getKeepAliveTime(TimeUnit.SECONDS) + "s");
System.out.println(" → " + risk);
}
static void shutdownQuietly(ExecutorService pool) throws InterruptedException {
pool.shutdown();
pool.awaitTermination(3, TimeUnit.SECONDS);
}
}