1.概述
在Android开发中,不能在主线程进行耗时操作,运行耗时操作必须创建子线程来运行。在一些频繁的耗时操作做(如ListView中图片下载),如果每次进行耗时操作都创建一个子线程。这样的话如果进行管理所创建的子线程,它们之间相互竞争,很可能由于占用过多资源导致OOM或者死机。而且每次创建线程、销毁线程都会有资源的消耗,而线程池可以很好解决这类的问题。
线程池的优点:
1.减少资源的开销:减少了每次创建线程、销毁线程的开销。
2.提高响应速度,每次请求到来时,由于线程的创建已经完成,可以直接执行任务,因此提高了响应速度。
3.线程便于管理:线程池可以对线程的创建与停止,线程数量等等因素加以控制,使得线程在一种可控的范围内运行。
4.线程池提供了定时,定期以及可控线程数等功能的线程池。
2.ThreadPoolExecutor
构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
...
}
主要参数含义:
1. corePoolSize
线程池中的核心线程数,默认情况下,核心线程是已知存活在线程池中,即使他们在线程池中处于闲置状态。
2. maximumPoolSize
线程池中所容纳的最大线程数,如果活动的线程达到这个数值以后,后续的新任务将会被阻塞。包含:核心线程数+非核心线程数。
3. keepAliveTime
非核心线程闲置时的超时时长,对于非核心线程,闲置时间超过这个时间,非核心线程就会被回收。只有对ThreadPoolExecutor的allowCoreThreadTimeOut属性设为true的时候,这个超时时间才会对核心线程产生效果。
4. unit
用于指定keepAliveTime参数的时间单位.可以使用的单位有天(TimeUnit.DAYS),小时(TimeUnit.HOURS),分钟(TimeUnit.MINUTES),毫秒(TimeUnit.MILLISECONDS),微秒(TimeUnit.MICROSECONDS, 千分之一毫秒)和毫微秒(TimeUnit.NANOSECONDS, 千分之一微秒);
5. workQueue
线程中保存等待执行的任务的阻塞队列。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。有下面几种队列可以选择:
ArrayBlockingQueue:
限定队列的长度,如果如果没有达到核心线程数,则新建线程(核心线程)处理任务;如果当前线程数达到了核心线程数,则入队列等待。如果队列已经满了,则新建线程(非核心线程)执行任务。如果总线程数达到了最大线程数,并且队列也满了,则发生错误。
SynchronousQueue:
接收到任务的时候,会直接交给线程处理,而不保留它。如果所有的线程都在工作,就新建线程来处理任务。使用这个队列的时候,都把最大线程数指定为Integer.MAX_VALUE。
LinkedBlockingQueue:
接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程等于核心线程数,则进入队列等待。由于这个队列没有最大值,则所有操作核心线程数的任务都被添加到队列中,所以最大线程数的设定失效。
3.实例
public class MainActivity extends AppCompatActivity {
private volatile int mNum =0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadPoolExecutor mPool=new ThreadPoolExecutor(5,20,30, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
for (int i = 0; i <100 ; i++) {
Runnable runnable= new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
mNum++;
Log.e("zzw","mNum="+mNum);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mPool.execute(runnable);
}
}
}
结果:
4.四种线程池类
Java中四种具有不同功能常见的线程池。他们都是直接或者间接配置ThreadPoolExecutor来实现他们各自的功能。这四种线程池分别是newFixedThreadPool,newCachedThreadPool,newScheduledThreadPool和newSingleThreadExecutor。
4.1 newFixedThreadPool:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
这是一种线程数量固定的线程池,核心线程数等于最大线程数。如果线程处于空闲状态,它们并不会被回收。除非这个线程池被关闭。
4.2 newCachedThreadPool:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
线程数量不固定的线程池,它只有非核心线程,并且最大线程数为Int的最大值。当线程池中的线程都处于活动状态的时候,线程池就会创建一个新的线程来处理任务。该线程池中的线程超时时长为60秒,所以当线程处于闲置状态超过60秒就会被回收。如果所有的线程都处于闲置状态超过60秒,则 newCachedThreadPool 中是不存在任何线程的,这时它几乎不占用任何的系统资源。
4.3 newScheduledThreadPool:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
它的核心线程数是固定的,总的线程数是Int的最大值,非核心线程的超时时长为0,也就是当非核心线程处于闲置状态的时候就会被立即收回。
4.4 newSingleThreadExecutor:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
在这个线程池中只有一个核心线程,任务队列大小没有闲置,也就是一个任务处于活动状态的时候,其他任务都会在任务队列中等候依次执行。