读完开发艺术探讨做的一些总结。
介绍:
在操作系统中,线程是操作系统调度最小的单元,同时线程又是一种受限的资源系统,既线程不可能无限制的生产,而且线程的创建和销毁都会有相应的开销。
在android开发中,从用途上来说,android 主要分为主线程和子线程,主线程负责处理和界面相关的事情,子线程往往处理耗时的操作。(在java中默认情况下,一个进程只有一个线程,这个线程就叫主线程,主线程在任何时候都必须有较高的响应速度,否则就会产生一种界面卡顿的感觉。如果在主线程中执行耗时操作那么容易导致程序无法及时响应,这个时候子线程就派上用处,子线程也叫工作线程,除了主线程意外的都是子线程)
通俗的理解就是一个公司一般只会有一位老板,老板多了做事情容易乱套,每个子线程都是老板手下的业务人员,老板一般只处理大事件,负责一些活动的签字行为等,当事情的具体细节老板就会交给他手下的员工去处理,这样就不会影响老板谈其它的生意发家致富了。
在android中除了Thread外,系统本身也有许多扮演子线程的角色,比如:
AsyncTask,IntentService等,不过这些本质上依然是传统的线程。
Android线程池
优点:
1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
2.有效的控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
3.能够对线程进行简单的管理,并提供定时执行及指定间隔循环执行等功能。
Android中的线程池来源与java中的Executor,真正实现为ThreadPoolExecutor。ThreadPoolExecutor提供了一系列参数,通过不同的参数可以创建功效不同的线程池。接下来先介绍一下ThreadPoolExecutor。
ThreadPoolExecutor
首先看一下ThreadPoolExecutor比较常用的一个构造方法:
corePoolSize (线程的核心数,默认情况下核心线程会一直在线程 中存活,跟allowCoreThreadTimeOut有关) maximumPoolSize (线程池能够容纳的最大线程数,当活动线程 数大道这个数值后,后续的新任务将会被阻塞) keepAliveTime (非核心线程闲置的超时时长,超过后非核 心线程会被回收,allowCoreThreadTimeOut为true时,对核心线程 也有效) unit (枚举单位,代表keepAliveTime的时间单位) workQueue (线程池中的任务列队,通过线程池的execute 方法提交的Runnable对象会存储在这个参数中) threadFactory (线程工厂,为线程池提供创建新线程的功能 threadFactory是一个接口,它只有一个方法:ThreadnewThread(Runnable r)) */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
ThreadPoolExecutor执行任务时候的大致规则:
1.如果线程池中的线程数量没有大道核心线程的数量,那么会直接启动一个核心线程来执行任务。
2.如果线程池中的线程数量已经达到或者超过核心线程数量,那么任务会被插入到任务列队中排队等待执行。
3.如果步骤2中无法将任务插入到任务列队中,这往往是由于任务列队已满,这个时候如果线程数量没有达到线程池中规定的最大值,那么会立刻启动一个非核心线程来执行任务。
4.如果步骤3中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionExecutionHandler的rejectedExecution方法来通知调用者。(参数不常用)
(allowCoreThreadTimeOut方法只有在ThreadPoolExecutor中实现了)
之前说到过的AsyncTask的源码中就有ThreadPoolExecutor的具体实现,可以看一下,接下来自己简单实现一个线程池:
private void initThreadPoolExecutor(){ int corePool = 5; int maxPool = 10; long keppTime = 10000; //BlockingQueue是一个接口 BlockingDeque<Runnable> poolQueue = new LinkedBlockingDeque<>(100); ThreadFactory threadFactory = new ThreadFactory() { @Override public Thread newThread(@NonNull Runnable r) { return null; } }; Executor executor = new ThreadPoolExecutor(corePool,maxPool,keppTime, TimeUnit.MILLISECONDS,poolQueue,threadFactory); }
每个参数之前的备注中有,应该很好理解其中的意思。
在Android中常用的线程池有4种,它们都直接或者间接地通过配置ThreadPoolExecutor来实现自己的功能特性的,
在Executors中有很多工厂方法,可以直接实例出来这些对象。
1.FixedThreadPool
通过Executors的newFixedThreadPool方法来创建,我们首页来看看他的实现方法:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); } public LinkedBlockingQueue() { this(Integer.MAX_VALUE); }
一般情况下,可以看到只用传入一个线程的具体数量就可以了,在其内部中,核心线程和最大线程是相同的,即代表只有核心线程,这意味着它能够更加快速的响应外界的请求。而且超时为0代表当线程为控件状态时,它们不会被回收,除非线程池被关闭。实例化的LinkedBlockingQueue长度不限,则代表新任务都会处于等待状态,直到有线程空闲出来。其实就跟字面意思一样,这是一个固定线程数的线程池。
下面介绍一下简单的使用方法:
Runnable runnable = new Runnable() { @Override public void run() { } }; ExecutorService fixed = Executors.newFixedThreadPool(5); fixed.execute(runnable);
2.CachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
通过Executors的newExecutorService 方法来创建,由上可以看到,它没有核心线程,只有不限制的非核心线程,而且有超时机制,当超过60秒钟后,线程就会被回收。由此可以看出只要有任务进来时,就会有线程去执行,当任务完成一段时间后,线程就会被回收,当闲置状态的时候,线程池中实际上是没有任务线程的,几乎不占用任何系统资源。这类线程比较适合执行大量的耗时较少的任务。
简单使用方式:
Runnable runnable = new Runnable() { @Override public void run() { } }; ExecutorService cache = Executors.newCachedThreadPool(); cache.execute(runnable);
3.ScheduledThreadPoolExecutor
Runnable runnable = new Runnable() { @Override public void run() { } }; public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
通过Executors的newScheduledThreadPool方法来创建,核心线程固定,最大线程数量没有限制,当非核心线程闲置时会被立刻回收,其中queue的类型是一个DelayedWorkQueue(),则代表这是一个用来执行延时任务,或者重复周期性的任务。
简单使用方法:
ScheduledExecutorService schedule = Executors.newScheduledThreadPool(3); //1000毫秒之后执行 schedule.schedule(runnable,1000,TimeUnit.MILLISECONDS); //1000毫秒后执行,每隔10000毫秒执行一次 schedule.scheduleAtFixedRate(runnable,1000,10000,TimeUnit.MILLISECONDS);
4.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
这个线程内部只有一个核心线程,这么做可以确保所有的任务都在一个线程中按顺序执行,这样统一所有的外界任务到一个线程中,使得在这些任务之间不需要处理线程同步的问题。
简单使用方式:
Runnable runnable = new Runnable() { @Override public void run() { } }; ExecutorService signle = Executors.newSingleThreadExecutor(); signle.execute(runnable);
其中当线程不使用的时候可以用shutdown()方法,来关闭使用。
作者:noodleszz
链接:https://www.jianshu.com/p/891d6e349268
共同学习,写下你的评论
评论加载中...
作者其他优质文章