线程池的概念大家应该都很清楚,帮我们重复管理线程,避免创建大量的线程增加开销。
除了降低开销以外,线程池也可以提高响应速度,了解点 JVM 的同学可能知道,一个对象的创建大概需要经过以下几步:
- 检查对应的类是否已经被加载、解析和初始化
- 类加载后,为新生对象分配内存
- 将分配到的内存空间初始为 0
- 对对象进行关键信息的设置,比如对象的哈希码等
- 然后执行 init 方法初始化对象
创建一个对象的开销需要经过这么多步,也是需要时间的嘛,那可以复用已经创建好的线程的线程池,自然也在提高响应速度上做了贡献。
public class ThreadPool { //创建自己的线程池 //一、.先定义线程池的几个关键属性值 private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();//核心线程数是cpu数的两倍 private static final int MAXIMUM_POOL_SIZE = 64;//线程池最大的线程数 private static final long KEEP_ALIVE_TIME = 1; //空闲线程保持存活时间为1秒 //二、.然后根据处理的任务类型选择不同的阻塞队列 /* 线程池中使用的队列是 BlockingQueue 接口,常用的实现有如下几种: 1. ArrayBlockingQueue:基于数组、有界,按 FIFO(先进先出)原则对元素进行排序 2. LinkedBlockingQueue:基于链表,按FIFO (先进先出) 排序元素 吞吐量通常要高于 ArrayBlockingQueue Executors.newFixedThreadPool() 使用了这个队列 3. SynchronousQueue:不存储元素的阻塞队列 每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态 吞吐量通常要高于 LinkedBlockingQueue Executors.newCachedThreadPool使用了这个队列 4.PriorityBlockingQueue:具有优先级的、无限阻塞队列*/ private final BlockingQueue<Runnable> mWorkQueue = new LinkedBlockingQueue<>(128); //三、创建自己的ThreadFactory //在其中为每个线程设置个名称 //获取本类的类名简称Class.getName():以String的形式,返回Class对象的“实体”名称; //Class.getSimpleName():获取源代码中给出的“底层类”简称。 private final String TAG = this.getClass().getSimpleName(); private final ThreadFactory DEFAULT_THREAD_FACTORY = new ThreadFactory() { //AtomicInteger提供原子操作来进行Integer的使用,因此十分适合高并发情况下的使用。AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。 private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r,TAG + "#" +mCount.getAndIncrement()); thread.setPriority(Thread.NORM_PRIORITY);//设置线程的优先级别,值越小,级别越高,这种不是绝对的,只是几率大。 return thread; } }; //四、然后创建线程池 private ThreadPoolExecutor mExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE,//核心线程的数量 MAXIMUM_POOL_SIZE, //最大线程数量 KEEP_ALIVE_TIME,//超出核心线程数量以外的线程空余存活时间 TimeUnit.SECONDS,//存活时间的单位 mWorkQueue,//保存待执行任务的队列 DEFAULT_THREAD_FACTORY,//创建新线程使用的工厂 new ThreadPoolExecutor.DiscardOldestPolicy() // 当任务无法执行时的处理器 ); private static volatile ThreadPool mInstance = new ThreadPool(); public static ThreadPool getInstance(){ return mInstance; } public void addTask(Runnable runnable){ mExecutor.execute(runnable);//提交任务的方法 还有一个就是 mExecutor.submit(),提交需要返回值的任务,
//submit()
有三种重载,参数可以是 Callable
也可以是 Runnable
。
//同时它会返回一个 Funture
对象,通过它我们可以判断任务是否执行成功。
//获得执行结果调用 Future.get()
方法,这个方法会阻塞当前线程直到任务完成}
//线程池即使不执行任务也会占用一些资源,所以在我们要退出任务时最好关闭线程池。 //有两个方法关闭线程池 // 1.将线程池设置为 STOP,然后尝试停止所有线程,并返回等待执行任务的列表 @Deprecated public void shutDownNow(){ mExecutor.shutdownNow(); } //2.将线程池的状态设置为 SHUTDOWN,然后中断所有没有正在执行的线程 //它们的共同点是:都是通过遍历线程池中的工作线程,逐个调用 Thread.interrup() 来中断线程,所以一些无法响应中断的任务可能永远无法停止(比如 Runnable)。 @Deprecated public void shutDown(){ mExecutor.shutdown(); } }
想更深了解线程池,请点击这个链接
:https://blog.csdn.net/mine_song/article/details/70948223