项目中很多地方使用了线程池,线程之间一般没有交集,如果线程间有共享变量或者共享资源,如何实现线程之间通信,如何保障共享资源的安全性。
目录
2.5 自定义线程池(ThreadPoolExecutor)
1. 创建线程的方式
1.1继承Thread
Thread是java.lang包中的类,实现了Runnable接口,并重写了run方法。
所以可以直接继承Thread类,并重写Thread类中的run方法即可,如下
public class MyThread extend Thread{
//重新Thread类中的方法run()
@Override
public void run(){
System.out.printIn("--线程执行的内容--");
}
}
public class myObject{
MyThread t = new MyThread();
t.start();
}
1.2实现Callable
Callable是java.util.concurrent并发包中的接口
通过 FutureTask 获取线程执行结果,支持异常抛出,需要异步任务返回结果时,需要将Callable封装到FutureTask中,因为Thread类构造器只接收Runnable参数,FutureTask继承Runable接口
public class MyCallable implement Callable<String>{
@Override
public String call() throws Exception{
return "执行call方法";
}
}
//使用FutureTask封装
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread t = new Thread(futureTask);
t.start();
//获取执行结果
String resutl = futureTask.get();
1.3实现Runnable
其中Runnable接口中只有一个抽象方法run(),无返回值
public class MyRunnable implement Runnable{
@Override
public void run(){
//执行的内容
System.out.println("执行内容");
}
}
//使用
Thread t = new Thread(new MyRunnable());
t.start();
//使用lambda表达式
new Thread(()->{
System.out.println("执行内容")
}).start();
1.4创建线程池
使用submit提交任务到线程池,可以获取到执行结果数据;submit方法接收Callable参数,submit也可以接收无返回值的Runnable
<T> Future<T> submit(Callable<T> task); Future<?> submit(Runnable task);
//创建线程池
ExecutorService executorService = new ThreadPoolExecutor(32,32,0L,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1000),new ThreadPoolExecutor.CallerRunsPolicy());
//线程池中提交任务,需要返回值的用submit,往线程池中提交100次任务
List<Future<String>> futures = new ArrayList<>();
for(int i = 0;i<100;i++){
futures.add(executorService.submit(()->{
return "执行内容";
}));
}
//获取结果
List<String> result = new ArrayList<>();
for(Future<Stirng> future : futures){
try{
result.add(future.get());
}catch(Exception e){
//
}
}
也可以用Executor中的方法void execute(Runnable command)提交任务;
对比总结:
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
继承 Thread | 简单直接 | 单继承限制,扩展性差 | 简单测试(不推荐生产使用) |
实现 Runnable | 解耦任务,支持 Lambda | 无返回值 | 大多数异步任务 |
实现 Callable | 支持返回值和异常 | 需配合 FutureTask 使用 | 需要结果反馈的任务 |
| 线程池 | 资源可控,性能最优 | 需手动配置参数 | 高并发生产环境 |
2. 线程池参数
2.1 固定大小的线程池
- 创建方式:
ExecutorService executor = Executors.newFixedThreadPool(int nThreads); - 特点:
- 线程数量固定(
nThreads),即使有空闲线程也不会回收。 - 任务队列是无界的(
LinkedBlockingQueue),可能导致内存溢出(OOM)。
- 线程数量固定(
- 适用场景:
- 适合处理长期稳定的并发任务(如服务器请求处理)。
2.2 单线程池
- 创建方式:
ExecutorService executor = Executors.newSingleThreadExecutor(); - 特点:
- 只有一个工作线程,保证任务按提交顺序串行执行。
- 任务队列无界(
LinkedBlockingQueue)。
- 适用场景:
- 需要保证任务顺序执行的场景(如日志写入)。
2.3 可缓存线程池
- 创建方式:
ExecutorService executor = Executors.newCachedThreadPool(); - 特点:
- 线程数量动态扩展(空闲线程默认60秒回收)。
- 任务队列不存储任务(
SynchronousQueue),直接交给线程执行。 - 极端情况下可能创建大量线程,导致资源耗尽。
- 适用场景:
- 短时异步任务(如HTTP请求)。
2.4 定时任务线程池
- 创建方式:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(int corePoolSize); - 特点:
- 支持定时或周期性任务(如
scheduleAtFixedRate)。 - 核心线程数固定,非核心线程空闲时回收。
- 支持定时或周期性任务(如
- 适用场景:
- 定时任务(如心跳检测、数据同步)。
2.5 自定义线程池(ThreadPoolExecutor)
- 创建方式:
ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, // 核心线程数 maximumPoolSize, // 最大线程数 keepAliveTime, // 空闲线程存活时间 TimeUnit, // 时间单位 workQueue // 任务队列(如ArrayBlockingQueue) ); - 特点:
- 完全可控的参数(队列类型、拒绝策略等)。
- 避免无界队列导致的OOM问题。
- 适用场景:
- 需要精细控制线程池行为的场景。
1553

被折叠的 条评论
为什么被折叠?



