Java线程池是一种管理和复用线程的机制,它通过在应用程序中维护一组工作线程,有效地管理并发任务的执行。线程池的主要目的是降低线程创建和销毁的开销,并提高程序性能。Java通过java.util.concurrent
包提供了丰富的线程池支持,其中最常用的是ThreadPoolExecutor
类。
import java.util.concurrent.*;
public class CustomThreadPoolExample {
public static void main(String[] args) {
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 5000;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
ExecutorService executorService = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, workQueue);
for (int i = 0; i < 10; i++) {
final int taskNumber = i;
executorService.submit(() -> {
System.out.println("Task " + taskNumber + " executed by thread " + Thread.currentThread().getName());
});
}
executorService.shutdown();
}
}
import java.util.concurrent.*;
public class FutureExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Callable<String> callableTask = () -> {
Thread.sleep(2000); // 模拟耗时任务
return "Task completed";
};
Future<String> future = executorService.submit(callableTask);
System.out.println("Main thread continues to do other work");
try {
// 阻塞,等待任务完成并获取结果
String result = future.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
ThreadPoolExecutor的主要参数和组件:
-
核心线程数(corePoolSize):
- 线程池中保持的最小线程数。
- 在线程池创建后,即使线程处于空闲状态,也会一直存在,除非调用了
allowCoreThreadTimeOut(true)
。
-
最大线程数(maximumPoolSize):
- 线程池中允许的最大线程数。
- 当工作队列满了且当前线程数小于最大线程数时,会创建新的线程执行任务。
-
线程存活时间(keepAliveTime)和时间单位(unit):
- 在线程池中的空闲线程的最大存活时间。
- 超过这个时间,空闲线程将被终止,直到线程数不超过核心线程数。
-
工作队列(workQueue):
- 用于保存等待执行的任务的阻塞队列。
- 常用的队列包括
LinkedBlockingQueue
、ArrayBlockingQueue
、SynchronousQueue
等。
-
线程工厂(threadFactory):
- 用于创建新线程的工厂。
-
拒绝策略(RejectedExecutionHandler):
- 当工作队列和线程池都满了,新任务无法被处理时的策略。
- 常用的策略有
AbortPolicy
、CallerRunsPolicy
、DiscardPolicy
等。
线程池的生命周期:
-
RUNNING:
- 线程池处于正常运行状态。
-
SHUTDOWN:
- 不再接受新任务,但会处理队列中的任务。
-
STOP:
- 不再接受新任务,不再处理队列中的任务,同时会中断正在执行的任务。
-
TIDYING:
- 所有任务都已终止,workerCount为0,线程池将转到TIDYING状态。
-
TERMINATED:
- 在执行完
terminated()
钩子方法后,线程池最终将会达到TERMINATED状态。
- 在执行完
ThreadLocal
ThreadLocal
是Java中用于在多线程环境下保持变量的线程局部副本的工具类。每个线程都可以独立地访问自己的副本,而不会影响其他线程的副本。这使得在多线程环境下能够方便地存储和获取线程私有的变量。
以下是ThreadLocal
的基本使用方式:
public class ThreadLocalExample {
private static final ThreadLocal<String> threadLocalVariable = new ThreadLocal<>();
public static void main(String[] args) {
// 在主线程设置ThreadLocal变量
threadLocalVariable.set("Main Thread Value");
// 创建并启动新线程
Thread newThread = new Thread(() -> {
// 在新线程中获取ThreadLocal变量
String value = threadLocalVariable.get();
System.out.println("New Thread Value: " + value);
});
newThread.start();
}
}
在这个例子中,ThreadLocal
对象被声明为静态的,可以在类的任何地方访问。在主线程中,通过set
方法设置了一个字符串值。然后,创建了一个新线程,在新线程中通过get
方法获取了ThreadLocal
变量的值。由于每个线程都有自己的副本,所以修改一个线程的副本不会影响其他线程的副本。
ThreadLocal的一些注意事项:
-
初始值: 可以通过
initialValue()
方法或withInitial(Supplier)
方法设置ThreadLocal
的初始值。private static final ThreadLocal<String> threadLocalVariable = ThreadLocal.withInitial(() -> "Default Value");
-
内存泄漏:当
ThreadLocal
不再被使用时,及时调用remove()
方法以防止内存泄漏。threadLocalVariable.remove();threadLocalVariable.remove();
-
继承性:子线程会继承父线程的
ThreadLocal
变量。但在子线程中修改变量值不会影响父线程的副本,反之亦然。 -
避免共享:
ThreadLocal
主要用于在单个线程内共享变量,不建议将它用于线程间共享变量的场景。