ThreadPoolExecutor线程池的一些基本知识,创建
ThreadPoolExecutor对象,这个对象是管理线程池的
image下面是工作流程,看图容易理解,所以可以看到 核心线程池跟队列都满了,最大线程池没满的话就是创建新的线程,最大的都满了,则会执行饱和策略。基本是什么没满用什么
image.png
饱和策略
image还有一个自定义的策略,这个有很多资料
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
while (e.getQueue().remainingCapacity() == 0);
e.execute(r);
}
}
remainingCapacity接口,主线程只要不断获取空余个数,是0就继续获取,直到不是0为止,这个方法不错。
我测试了10万级最快是3秒,如果一个线程执行完任务需要一秒,则10万级会是1分30秒。
/**
* @Description:线程池管理类
**/
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThreadPoolManager {
/**
* 说明:下面这些常量是根据AsyncTask的源码配置的,大家可以根据自己需求自行配置
*/
//根据cpu的数量动态的配置核心线程数和最大线程数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数 = CPU核心数 + 1
private static final int CORE_POOL_SIZE = CPU_COUNT + 1050;
//线程池最大线程数 = CPU核心数 * 2 + 1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 100000;
//非核心线程闲置时间 = 超时1s
private static final int KEEP_ALIVE = 1;
// 要确保该类只有一个实例对象,避免产生过多对象消费资源,所以采用单例模式
private MyThreadPoolManager() {
}
private static MyThreadPoolManager sInstance;
public synchronized static MyThreadPoolManager getsInstance() {
if (sInstance == null) {
sInstance = new MyThreadPoolManager();
}
return sInstance;
}
// 线程池的对象
private ThreadPoolExecutor executor;
// 使用线程池,线程池中线程的创建完全是由线程池自己来维护的,我们不需要创建任何的线程
// 我们所需要做的事情就是往这个池子里面丢一个又一个的任务
public void execute(Runnable r) {
if (executor == null) {
/**
* corePoolSize:核心线程数
* maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
* keepAliveTime:非核心线程闲置时间超时时长
* unit:keepAliveTime的单位
* workQueue:等待队列,存储还未执行的任务
* threadFactory:线程创建的工厂
* handler:异常处理机制
*/
executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
}
try {
executor.execute(r);// 把一个任务丢到了线程池中
} catch (Exception e) {
e.printStackTrace();
}
}
public void cancel(Runnable r) {
if (r != null) {
executor.getQueue().remove(r);//把任务移除等待队列
}
}
}
然后是线程类
/**
* @Description:线程类
**/
public class MyThread implements Runnable{
public void run() {
long time = System.currentTimeMillis();
System.out.println("开始启动线程 ssss"+ Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId()+" 线程结束 dddd time:"+(System.currentTimeMillis()-time));
}
}
再然后是测试类
/**
* @Description:测试类
**/
public class Atest {
@Test
public void te()throws Exception {
System.out.println(Thread.currentThread().getId()+" 2222222 enter time:" + System.currentTimeMillis());
MyThreadPoolManager myThreadPoolManager=MyThreadPoolManager.getsInstance();
for (int i=0;i<100000;i++){
MyThread myThread=new MyThread();
myThreadPoolManager.execute(myThread);
}
System.out.println("3333leave time:" + System.currentTimeMillis());
Thread.sleep(100000); // 因为junit结束会结束jvm,所以让它等会异步线程
}
}
ArrayBlockingQueue 和 LinkedBlockingQueue 对比
ArrayBlockingQueue和LinkedBlockingQueue都支持blockingQueue的概念,就存取block,可以说两者很相像,那么具体有哪些区别呢?
内部存储
ArrayBlockingQueue 内部是实例化一个Object数组来存储
LinkedBlockingQueue 内部是一个内部静态类Node,维护本身的内容和next一个link.
容量和性能
这里做了简单的测试,和看了源码和相关作者回复的邮件。
占用内存来讲。从表面来看,array会小一点,Node比较大一点。但是作者说只有不太会array比node的可能。只有在array超过1/2, 1/3的时候才可能出现。
性能。在源码注释中,提到ArrayBlockingQueue支持一个是否对wait的线程进行排序,然后FIFO,这个有点消耗,但默认是没有这个工作的。然后在LinkedBlockingQueue中说Linked based queues经常会比array based queues性能高一点,但是不像array那样容易预测结果。然后ArrayBlockingQueue中维护一个锁,LinkedBlockingQueue中维护两个锁,这样Linked阻塞的次数会减少,从而性能更高。
网友评论