thread pool一般被用来解决两个问题:当处理大量的同步task的时候,它能够避免thread不断创建销毁的开销。通过使用thread pool可以限制这些任务所消耗的资源,比如最大线程数,比如最大的消息缓冲池。ThreadPoolExecutor不仅仅是简单的多个thread的集合,它还带有一个消息队列
整个ThreadPoolExecutor的任务处理有4步操作:
1. 初始的poolSize < corePoolSize,提交的runnable任务,会直接做为new一个Thread的参数,立马执行scheduledThreadPool.schedule(runnable, 10, TimeUnit.SECONDS);//10s之后运行runnable这个task
参考 ThreadPoolExecutor原理及使用
public class Test {
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask#" + mCount.getAndIncrement());
}
};
private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(2);
//private static final SynchronousQueue sPoolWorkQueue = new SynchronousQueue();
public static final ExecutorService THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(2, 7, 10, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
private static void run(ExecutorService threadPool) {
for (int i = 1; i < 8; i++) {
final int taskID = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int i = 1; i < 5; i++) {
try {
Thread.sleep(1000);// 为了测试出效果,让每次任务执行都需要一定时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第" + taskID + "次任务的第" + i + "次执行");
}
}
});
}
// threadPool.shutdown();// 任务执行完毕,关闭线程池
}
public static void main(String[] args) throws InterruptedException {
// 创建可以容纳3个线程的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(6);
// 线程池的大小会根据执行的任务数动态分配
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 创建单个线程的线程池,如果当前线程在执行任务时突然中断,则会创建一个新的线程替代它继续执行任务
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 效果类似于Timer定时器
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
run(THREAD_POOL_EXECUTOR);
// run(fixedThreadPool);
// run(cachedThreadPool);
// run(singleThreadPool);
// run(scheduledThreadPool);
Thread.sleep(10000);
System.out.println("10s过后");
}
}
如果此时
public static final ExecutorService THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS,这个的原理网上一大把。。就不多分析了
onPreExecute 运行在主线程,一开始的准备工作
doInBackground 运行在子线程,所以可以做耗时的工作,运行过程中通过handler发消息给main线程,调用onProgressUpdate方法。 运行结束通过handler发消息给main线程,调用onPostExecute方法
onProgressUpdate 据上可知运行在main线程
onPostExecute 据上可知运行在main线程
给下参考博客
1.Android应用AsyncTask处理机制详解及源码分析
2.Android AsyncTask 源码解析
自己总结一下:
Android3.0以上
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
public final AsyncTask executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
所以一个异步task只能运行一次,否则报IllegalStateException异常,默认情况使用sDefaultExecutor
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
SERIAL_EXECUTOR是静态的,所以一个进程就这么一个,所有asynctask共享一个SERIAL_EXECUTOR管理
虽然THREAD_POOL_EXECUTOR这个支持最多MAXIMUM_POOL_SIZE个线程的并发,同时可以缓存128个任务,但是看SERIAL_EXECUTOR的定义可以发现,
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
r.run();只有当前asynctask运行完全,才会去执行finally中的scheduleNext()方法,执行把下一个任务放到THREAD_POOL_EXECUTOR线程池中运行。。所以THREAD_POOL_EXECUTOR最多并发的线程数其实只有CORE_POOL_SIZE.。。。但是在运行的绝对只有1个,其它4个处于idle态,所以说是单线程执行。 for(int i = 1 ;i <= 139 ; i++)
{
new MyAsyncTask().execute();
}
for(int i = 1 ;i <= 139 ; i++)
{
new MyAsyncTask().execute();
}
3.0以下,会发生异常:java.util.concurrent.RejectedExecutionException
首先定义一个异步任务,让线程休眠1s
public class MyAsynctask extends AsyncTask {
@Override
protected Object doInBackground(Object[] params) {
try {
Thread.sleep(1000);
BaseApp.Log("doInBackground: " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0; i < 150; i++) {
new MyAsynctask().execute();
//new MyAsynctask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
//new MyAsynctask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
new MyAsynctask().execute();
执行结果: 可以看到每1s执行一个任务。。但是第5个任务添加进来后THREAD_POOL_EXECUTOR就有五个线程了。。但是只有1个线程在运行,其它4个处于idle态,至于用那个线程执行task,结果是不固定的,,这个看cpu的调度,所有之后可能打印AsyncTask #1到5中的任何一个
11-05 17:50:46.521 28829-28855/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #1
11-05 17:50:47.524 28829-28956/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #2
11-05 17:50:48.530 28829-29033/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
11-05 17:50:49.531 28829-29078/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 17:50:50.532 28829-29124/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
11-05 17:50:51.533 28829-29124/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
11-05 17:50:52.533 28829-29124/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
............
11-05 17:51:12.636 28829-29078/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 17:51:13.637 28829-29078/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 17:51:14.644 28829-29033/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
11-05 17:51:15.645 28829-29033/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
............
new MyAsynctask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
这个不用说,跟情况1完全一样,因为execute()内部调用的就是executeOnExecutor(AsyncTask.SERIAL_EXECUTOR),所以单线程执行。。
new MyAsynctask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
执行结果:force close了有没有
Caused by: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@42c1ca70 rejected from java.util.concurrent.ThreadPoolExecutor@42b1e658[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 0]
因为此时150个任务,已经超过了MAXIMUM_POOL_SIZE+128了。。。在我的机子上cpu是4核,所以最多支持9+128=137个任务的提交,否则就抛出RejectedExecutionException异常。。如果此时150改成137,那么就不要抛异常啦,大于137都会抛RejectedExecutionException异常
本质,因为此时使用的不是SERIAL_EXECUTOR。。而是THREAD_POOL_EXECUTOR,所以此时是并发的处理150个任务的。。
android3.0以下,没有SERIAL_EXECUTOR,,,所以超过一定数量的任务也会抛这个异常
for (int i = 0; i < 100; i++) {
new MyAsynctask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
此时100小于137的,所以正常运行,可以发现,5个线程同时并发。。。
11-05 18:05:17.506 16953-16978/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #1
11-05 18:05:17.506 16953-16979/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #2
11-05 18:05:17.507 16953-16980/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
11-05 18:05:17.507 16953-16981/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 18:05:17.508 16953-16982/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
11-05 18:05:18.506 16953-16978/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #1
11-05 18:05:18.507 16953-16979/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #2
11-05 18:05:18.507 16953-16980/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
11-05 18:05:18.508 16953-16981/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 18:05:18.509 16953-16982/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
11-05 18:05:19.507 16953-16978/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #1
11-05 18:05:19.507 16953-16979/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #2
11-05 18:05:19.508 16953-16980/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #3
11-05 18:05:19.508 16953-16981/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #4
11-05 18:05:19.509 16953-16982/lbb.demo.test D/LiaBin: doInBackground: AsyncTask #5
................