本文将介绍 Java 中线程池的实现方法,包括常见的线程池类型及其核心参数配置。
chou403
/ Thread
/ c:
/ u:
/ 8 min read
线程池有几种实现方法具体参数是什么
在Java中,线程池是通过java.util.concurrent
包中的Executor
框架实现的。Executor
框架提供了多种线程池的实现,每种线程池都有不同的参数和用途。以下是几种常见的线程池实现及其具体参数:
1. ThreadPoolExecutor
这是最灵活和强大的线程池实现,可以通过构造函数来设置各种参数。
构造函数参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize: 核心线程数,即使在空闲时也会保留在线程池中的线程数。
- maximumPoolSize: 线程池允许的最大线程数。
- keepAliveTime: 当线程数超过核心线程数时,多余的空闲线程存活的时间。
- unit:
keepAliveTime
的时间单位。 - workQueue: 用于存放等待执行任务的队列。
- threadFactory: 用于创建新线程的工厂。
- handle: 用于处理任务拒绝的策略。
线程池示例
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // corePoolSize
10, // maximumPoolSize
60, // keepAliveTime
TimeUnit.SECONDS, // unit
new LinkedBlockingQueue<Runnable>(), // workQueue
Executors.defaultThreadFactory(), // threadFactory
new ThreadPoolExecutor.AbortPolicy() // handler
);
2. Executors 工厂方法
Executors
类提供了几种便捷的工厂方法来创建常用的线程池。
2.1. newFixedThreadPool(int nThreads)
创建一个固定大小的线程池。
固定大小线程池示例
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
2.2. newCachedThreadPool()
创建一个可缓存的线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收线程则新建线程。
可缓存线程池示例
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
2.3. newSingleThreadExecutor()
创建一个单线程的线程池,它会确保所有任务按照指定的顺序(FIFO, LIFO, 优先级)执行。
单线程线程池示例
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
2.4. newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性任务执行的线程池。
周期性线程池示例
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
3. 参数解释和选择
- corePoolSize 和 maximumPoolSize: 决定线程池在不同负载下的行为。对于固定线程池,
corePoolSize
和maximumPoolSize
是相同的;对于缓存线程池,maximumPoolSize
是Integer.MAX_VALUE
。 - keepAliveTime 和 unit: 用于控制非核心线程的存活时间。
- workQueue: 选择适当的队列类型(如
LinkedBlockingQueue
,SynchronousQueue
)对任务的调度策略影响很大。 - threadFactory: 允许自定义线程的创建方式,通常用于设置线程名称,优先级等。
- handler: 当任务添加到线程池中被拒绝时的处理策略,如
AbortPolicy
,CallerRunsPolicy
,DiscardPolicy
,DiscardOldestPolicy
。
通过合理设置这些参数,可以创建满足不同并发需求的线程池,实现高效的任务处理。
threadlocal 是干嘛的如何实现的
ThreadLocal
是 Java 中的一种机制,允许你为每个线程创建独立的变量副本。这些变量副本对每个线程是隔离的,因此一个线程无法访问另一个线程的ThreadLocal
变量。ThreadLocal
常用于在多线程环境中存储不希望被共享的线程局部变量,例如用户会话,数据库连接等。
ThreadLocal
的用途
- 线程安全: 避免多个线程访问共享变量导致的数据不一致和并发问题。
- 状态隔离: 为每个线程提供独立的变量副本,避免不同线程间的相互干扰。
- 简化代码: 简化了线程安全类的实现,无需显式使用锁机制。
ThreadLocal
的实现
使用ThreadLocal
非常简单,主要包括以下几个步骤:
-
创建
ThreadLocal
实例:private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("dd-MM-yyyy"); } };
-
设置值:
dateFormatHolder.set(new SimpleDateFormat("dd-MM-yyyy"));
-
获取值:
SimpleDateFormat dateFormat = dateFormatHolder.get();
-
移除值(推荐使用,以避免内存泄漏):
dateFormatHolder.remove();
TrealLocal 示例代码
以下是一个完整的示例,展示如何在多线程环境中使用ThreadLocal
来存储和获取每个线程的独立变量:
public class ThreadLocalExample {
// 创建一个ThreadLocal变量,用于存储每个线程独立的SimpleDateFormat实例
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder =
ThreadLocal.withInitial(() -> new SimpleDateFormat("dd-MM-yyyy"));
public static void main(String[] args) throws InterruptedException {
// 创建多个线程,并启动它们
Thread t1 = new Thread(() -> printDate("Thread-1"));
Thread t2 = new Thread(() -> printDate("Thread-2"));
Thread t3 = new Thread(() -> printDate("Thread-3"));
t1.start();
t2.start();
t3.start();
// 等待所有线程执行完毕
t1.join();
t2.join();
t3.join();
}
private static void printDate(String threadName) {
// 获取当前线程的SimpleDateFormat实例
SimpleDateFormat dateFormat = dateFormatHolder.get();
Date now = new Date();
// 打印当前线程的日期格式
System.out.println(threadName + ": " + dateFormat.format(now));
// 移除当前线程的ThreadLocal变量,防止内存泄漏
dateFormatHolder.remove();
}
}
在这个示例中,每个线程都会创建自己的SimpleDateFormat
实例并进行日期格式化操作,互不干扰,确保了线程安全。
ThreadLocal
的工作原理
ThreadLocal
的内部实现依赖于每个线程维护的一个ThreadLocalMap
对象。每个ThreadLocal
对象在ThreadLocalMap
中都有一个独立的条目,该条目的键是ThreadLocal
对象自身,值是实际的变量副本。
以下是ThreadLocal
的工作流程:
- 存储值: 当调用
ThreadLocal.set(T value)
方法时,当前线程的ThreadLocalMap
会将ThreadLocal
对象作为键,value
作为值存储起来。 - 获取值: 当调用
ThreadLocal.get()
方法时,当前线程的ThreadLocalMap
会使用ThreadLocal
对象作为键,查找对应的值并返回。 - 初始化值: 如果在调用
ThreadLocal.get()
方法时当前线程的ThreadLocalMap
中不存在对应的条目,会调用initialValue()
方法来初始化值并存储。 - 移除值: 调用
ThreadLocal.remove()
方法时,会从当前线程的ThreadLocalMap
中移除对应的条目,以避免内存泄漏。
通过这种机制,ThreadLocal
实现了每个线程独立的变量副本,确保了线程安全和数据隔离。