① java一般是如何定义一个线程池的?请看代码
private static ExecutorService taskPool = new ThreadPoolExecutor(16, 32
,200L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue(1000)
,new ThreadFactoryBuilder()
.setNameFormat("thread-自定义线程名-runner-%d").build());
注:这里的线程池中的参数后续会做介绍 ,你只需要知道 16是核心线程数、32是最大线程数即可。
② 那如何往线程池中加入任务呢?请看代码
public static void main(String[] args) {
taskPool.submit(new Runnable() {
@Override
public void run() {
// 你要在线程池中执行的代码...
}
});
}
submit方法中传入一个 Runnable对象即可, 是不是很简单,但是一般不是直接new 一个Runnable丢进线程池的,而是写一个类 ,去实现 Runnable,代码如下:
public class ATask implements Runnable {
private String a;
public ATask(String a) {
this.a = a;
}
public ATask() {}
@Override
public void run() {
// 写下你要在线程池中执行的代码...
System.out.println("a=" + a);
}
}
还没完 我经常需要在任务里面注入spring中的service 一般怎么处理呢?
来看代码 ,目标是把AService注入到ATask中并且调用它:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class B {
private static ExecutorService taskPool = new ThreadPoolExecutor(16,32,200L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue(1000),
new ThreadFactoryBuilder().setNameFormat("thread-thirdPushMsgJob-runner-%d").build());
// ① 在调用线程池之前注入AService到当前类
@Autowired
private AService aService;
public static void main(String[] args) {
// ② 将AService传入ATask中
ATask aTask = new ATask("aStr", aService);
// 任务提交到线程池
taskPool.submit(aTask);
}
}
public class ATask implements Runnable {
private String a;
private AService aService;
// ③ 对应的ATask需要一个包含 AService的构造函数
public ATask(String a, AService aService) {
this.a = a;
this.aService = aService;
}
public ATask() {}
@Override
public void run() {
// 写下你要在线程池中执行的代码...
// ④ 执行AService中的a()方法
aService.a();
}
}
注:上述线程池不能说是完美,但是也符合大多数使用场景了,但如果我想要获取线程池任务的处理结果怎么办呢?
③ 获取线程池的处理结果
3.1 首先多线程的任务不能再是实现 Runnable,而是实现Callable
// ① 实现Callable接口 【接口泛型即为线程的返回类型】
public class ATask implements Callable
注:可以看到 ATask得call方法已经有返回值了 那怎么获取这个返回值呢
3.2 获取线程得返回值
class B {
private static ExecutorService taskPool = new ThreadPoolExecutor(16,32,200L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue(1000),
new ThreadFactoryBuilder().setNameFormat("thread-thirdPushMsgJob-runner-%d").build());
public static void main(String[] args) throws
ExecutionException, InterruptedException {
ATask aTask = new ATask("aStr");
// 任务提交到线程池
Future
只需要接收submit方法的返回值 再get即可获取数据,需要注意的是 future.get()有可能出现异常,建议try-catch处理 future.get(),防止未知异常的出现导致线程任务未正确返回结果
④ 线程池的参数怎么调优?
来看看线程池中参数的释义:
那这些线程池参数都啥意思呢?我们来看
1. 核心线程数:有任务来了,判断到当前任务数量小于核心线程数时,就新建一个线程而不是把任务放入队列
2.最大线程数和任务队列:有任务来了,判断当前任务大于核心线程数时,就会往队列里面存放任务,只有当任务队列满了,才会创建新的线程来处理任务,但是线程池最多能有多少个任务是由最大线程数来决定的。 那在这里问问,最大线程数和任务队列都满了怎么破呢? 有个 线程池饱和策略 建议大家去搜索看,网上有很多讲的很好,我就不详讲了。