1.为什么要用线程池?
1.使用起来方便快捷
2.相比较于传统开启线程的方式,效率得到极大的提高,下面的代码可以证明
package xu.ba.dou;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @Package xu.ba.dou
* @Author 徐八斗
* @Date 2021/7/3 9:55
* @Version V1.0
*/
public class ThreadPoolTest {
public static void main(String[] args) throws InterruptedException {
simpleTest();
threadPoolTest();
}
/**
* 普通的开启线程的方式
*/
public static void simpleTest() throws InterruptedException {
long beginTime = System.currentTimeMillis();
List<Integer> list = new ArrayList<>();
Random rand = new Random(47);
for (int i = 0; i < 100000; i++) {
Thread thread = new Thread(() -> {
list.add(rand.nextInt());
});
thread.start();
thread.join();
}
long endTime = System.currentTimeMillis();
System.out.println(String.format("普通的开启线程的方式总共花了 %s ms", endTime - beginTime));
}
/**
* 通过线程池开启线程的方式
*/
public static void threadPoolTest() throws InterruptedException {
long beginTime = System.currentTimeMillis();
List<Integer> list = new ArrayList<>();
Random rand = new Random(47);
ExecutorService exec = Executors.newSingleThreadExecutor();
for (int i = 0; i < 100000; i++) {
exec.execute(() -> {
list.add(rand.nextInt());
});
}
exec.shutdown();
exec.awaitTermination(1, TimeUnit.DAYS);
long endTime = System.currentTimeMillis();
System.out.println(String.format("线程池开启线程的方式总共花了 %s ms", endTime - beginTime));
}
}
执行结果如下所示
通过上面的例子,可以看到,使用线程池开启线程之后,速度得到了质的飞越
2.线程池构造器中各个参数的含义是什么?
直接上源码
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
int corePoolSize 核心线程数
int maximumPoolSize 最大线程数
long keepAliveTime 非核心线程(最大线程-核心线程)的存活时间(核心线程一直存在,所以该字段对核心线程不起作用)
TimeUnit unit 存活时间的单位
BlockingQueue workQueue 存放任务的阻塞队列
ThreadFactory threadFactory 生产线程的工厂
RejectedExecutionHandler handler 拒绝策略
3.常见的线程池有哪些,区别是什么?
上源码
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
常见的线程池就是上面这三种
1.固定数量的线程池
核心线程数和最大线程数相等,队列使用无界阻塞队列,故而超出核心线程数的任务都会直接进入无界队列里
2.固定数量为1的单线程的线程池
核心线程数和最大线程数都是1,队列使用无界阻塞队列
3.缓存线程池
核心线程数为0,最大线程数是整型的最大值,队列使用的同步队列(只能存放一个任务)
4.为什么要使用自定义的线程池?
很明显上面三种常用的线程池都存在着一些问题
固定数据的线程池和单线程线程池都使用的是无界队列,那么当任务不断的添加,就有可能会导致内存溢出
而缓存线程池,由于随着任务的不断添加,会不断的添加线程,那么就会增加cpu的负担(因为要不断的切换来,切换去)
所以当我们使用线程池的时候,最后是能根据自己的需求去自定义一个线程池(如何定义,可参考上面的线程池构造方法的参数)