引子
关于线程池,在这里写出几种最顺手的写法,至于原理以及各种细节。放后面再填;
经过查证,凡是 以前new Thread()的地方,貌似都可以用线程池来执行,优化内存消耗。
代码
系统提供的4种预设线程池类:
1 Runnable runnable = new Runnable() { 2 @Override 3 public void run() { 4 Log.d("atm", "假装有执行过程·"); 5 } 6 }; 7 8 //第一类 9 // 全部由核心线程去实现,并不会被回收,没有超时限制和任务队列的限制,会创建一个定长线程池, 10 // 可控制线程最大并发数,超出的线程会在队列中等待 11 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4); 12 fixedThreadPool.execute(runnable); 13 14 //第二类 15 //该模式下线程数量不定的线程池,只有非核心线程,最大值为Integer.MAX_VALUE,会创建一个可缓存线程池, 16 // 如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程 17 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 18 cachedThreadPool.execute(runnable); 19 20 //第三类 21 //该模式下核心线程是固定的,非核心线程没有限制,非核心线程闲置时会被回收。 22 // 会创建一个定长线程池,执行定时任务和固定周期的任务 23 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4); 24 scheduledThreadPool.schedule(runnable, 2000, TimeUnit.SECONDS);//2000ms后执行。 25 scheduledThreadPool.scheduleAtFixedRate(runnable, 10, 1000, TimeUnit.MILLISECONDS);//延迟10ms后,每隔1000ms执行一次 26 27 //第四类, 28 //该模式下线程池内部只有一个线程,所有的任务都在一个线程中执行,会创建一个单线程化的线程池, 29 // 它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行 30 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); 31 singleThreadExecutor.execute(runnable);
不用系统的,而是自己定义各种参数:
1 import android.support.annotation.NonNull; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.Future; 5 import java.util.concurrent.LinkedBlockingDeque; 6 import java.util.concurrent.ThreadFactory; 7 import java.util.concurrent.ThreadPoolExecutor; 8 import java.util.concurrent.TimeUnit; 9 import java.util.concurrent.atomic.AtomicInteger; 10 11 /** 12 */ 13 public class CustomThreadPool { 14 15 private static final int CORE_POOL_SIZE = 3;//核心线程数目 16 private static final int MAX_POOL_SIZE = 20;//最大线程数,除了核心线程就是非核心线程 17 private static final int ALIVE_TIME = 5;//非核心线程允许闲置的最大时长 18 19 private static final CustomThreadPool instance; 20 21 private final ThreadPoolExecutor pool; 22 23 static { 24 instance = new CustomThreadPool(); 25 } 26 27 private CustomThreadPool() { 28 //参数逐个解析 29 /** 30 * @param 核心线程的数目,即使他们是闲置状态,也不会被回收,除非你设置 allowCoreThreadTimeOut,让核心线程也有超时时间(不过一般不这么做) 31 * @param 线程池的最大容量,可以容纳核心线程和非核心线程 32 * @param 当线程数目大于核心线程数,这个值是被回收的最大闲置时间,超出则会被回收 33 * @param 超时时间的单位(一般用秒,或者毫秒) 34 * @param 等待队列,当核心线程都在工作,而又有新的任务需要执行,这些任务则会先进入等待队列(但是如果进不去,或者队列满了,就会尝试用非核心线程) 35 * @param 生成线程的工厂(一般都会自己new 一个类继承ThreadFactory) 36 * @throws IllegalArgumentException 参数异常 37 * 可能抛出的异常, 38 * 比如,你把核心线程数设置为负数; 39 * 或者超时时间设置为负数 40 * 或者最大线程数是非正数; 41 * 或者最大线程数小于 核心线程数 42 * @throws NullPointerException 43 * 当 工作队列是空,或者 线程工厂,对象是空,就会报空指针 44 */ 45 pool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(), new MyThreadFactory()); 46 } 47 48 public static CustomThreadPool getInstance() { 49 return instance; 50 } 51 52 /** 53 * 执行,无返回值 54 * 55 * @param r 56 */ 57 public void execute(Runnable r) { 58 pool.execute(r); 59 } 60 61 /** 62 * 提交,有返回值 63 * 64 * @param r 65 * @return 66 */ 67 public Future<String> submit(Runnable r, String s) { 68 return pool.submit(r, s); 69 } 70 71 public Future<String> submit(Callable<String> callable) { 72 return pool.submit(callable); 73 } 74 75 private class MyThreadFactory implements ThreadFactory { 76 77 private final AtomicInteger mCount = new AtomicInteger(1); 78 79 @Override 80 public Thread newThread(@NonNull Runnable r) { 81 Thread thread = new Thread(r, "GWThreadPool-" + mCount.getAndIncrement()); 82 thread.setPriority(Thread.NORM_PRIORITY - 1); 83 thread.setDaemon(false); 84 return thread; 85 } 86 } 87 88 }
带返回值的执行,以及不带返回值的执行;
1 private void test2() { 2 //如果你想执行一个带返回值的任务,任务执行完成之后,返回结果,用下面的代码 3 try { 4 Callable<String> callable = new Callable<String>() {// 注意这里不是Runnable,而是Callable, 5 @Override 6 public String call() { 7 return "哈哈哈"; 8 } 9 }; 10 11 //````如果你想执行任务,并且要取执行完成之后的返回值,用submit吧 12 Future<String> s = CustomThreadPool.getInstance().submit(callable);//执行,submit 有返回值 13 //下面有5个API可供调用 14 /** 15 * 尝试取消任务的执行。这种尝试将会失败,当任务已经完成,已经被取消,或者因为某种原因不能被取消。 16 * 如果成功取消,这个任务还没开始的话,那这个任务将永远不会执行, 17 * 如果任务已经开始,那就要 mayInterruptIfRunning 参数值将会决定是否要尝试去终止任务;(true,尝试终止,false,不去尝试;至于为什么这里是尝试,而不是一定终止,参照本段开头;) 18 * 当这个方法返回,后来的调用isDone将会永远返回true,也就是说,取消也算做是完成? 19 * 后来的调用isCanceled 将会永远返回true,如果这个方法返回true的话。 20 * @param mayInterruptIfRunning 是否执行这个任务线程的线程能够被中断;true能够中断,false,将会继续执行直到完成; 21 * @return 返回值,false,如果这个任务不能被取消,典型的就是这个任务已经完成了·· 其他情况,返回true; 22 */ 23 s.cancel(true);// 取消任务,参数的意思是:是否允许在执行过程中中断; 如果true,不管是不是已经开始任务,都让他终止;false,如果已经开始了,就不终止了; 24 s.isDone();//是否已完成 25 s.isCancelled();// 是否已经被取消 26 27 String result = s.get();// 获取执行的结果,如果任务尚未执行完成,有可能会阻塞一段时间 28 String result2 = s.get(3, TimeUnit.SECONDS);//最多等待3秒,get的重载方法,因为有可能会阻塞,阻塞的时长不定,所以提供一个重载方法,指定阻塞的最大时间; 29 30 //````如果你只是想执行任务,不想要返回值,那么,用execute 31 Runnable runnable = new Runnable() { 32 @Override 33 public void run() { 34 Log.d("hahaha", "假装这里有代码"); 35 } 36 }; 37 CustomThreadPool.getInstance().execute(runnable); 38 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } catch (ExecutionException e) { 42 e.printStackTrace(); 43 } catch (TimeoutException e) { 44 e.printStackTrace(); 45 } 46 }