Android线程与线程池
Posted dx我是大雄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android线程与线程池相关的知识,希望对你有一定的参考价值。
一.特殊的线程
1.AsynTask
底层用到了线程池,封装了线程池和Handler,主要是为了方便开发者在子线程中更新UI
2.IntentService
内部采用HandlerThread来执行任务,当任务执行完毕后IntentService会自动退出,底层直接使用了线程(从任务执行的角度来看,IntentService的作用很像一个后台线程,但是IntentService是一种服务,他不容易被系统杀死从而可以尽量保证任务的执行)
3.HandlerThread
是一种具有消息循环的线程,在它的内部可以使用Handler,底层直接使用了线程
二.android中的线程形态
1.1 参数及方法介绍
1.AsyncTask是一个抽象的泛型类,它提供了Params,Progress和Result这三个泛型参数,其中Params表示参数的类型,Progress表示后台任务的执行进度的类型,而Result则表示后台任务的返回结果的类型。
如果AsyncTask确实不需要传递具体的参数,那么这三个泛型参数可以用Void来代替,AsyncTask这个类的声明如下所示。
public abstract class AsyncTask<Params ,Progress ,Result>
(1)onPreExecute
在主线程执行,在异步任务执行之前,此方法会被调用,一般可用于做一些准备工作
(2)doInBackground(Params...params)
在线程池中执行,此方法用于执行异步任务,params参数表示异步任务的的输入参数,在此方法中可以通过publishProgress方法来更新任务的进度,publicProgress方法会调用onProgressUpdate方法。另外此方法需要返回计算结果给onPostExecute
(3)onProgressUpdate(Progress...values)
在主线程中执行,当后台任务的执行进度发生改变时此方法会被调用。
(4)onPostExecute(Result result)
在主线程中执行,异步任务执行之后,此方法会被调用,其中Result参数是后台任务的返回值,即doInBackgroud的返回值
(5)onCancelled
在主线程中执行 异步任务取消时调用,这个时候onPostExecute则不会调用
1.2 AsyncTask在具体的使用过程中也是有一些条件限制
(1)AsyncTask的类必须在主线程中加载,这就意味着第一个访问AsncTask必须发生在主线程,当然这个过程在Android4.1及以上版本中已经被系统已经自动完成。在Android5.0的源码中,可以查看ActivityThread的main方法,他会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件(为什么要满足这个条件,因为要切回主线程的Handler必须是在主线程中创建,然后这个Handler是AsyncTask的内部静态类,所以这个类必须在主线程加载)
(2)AsyncTask的对象必须在主线程中创建
(3)Execute方法必须在UI线程调用
(4)一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行异常
(5)在Android1.6之前,AsyncTask是串行执行任务的,Android1.6的时候AsyncTask开始采用线程池里处理并行任务,但是Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务,尽管如此,在Android3.0以及后续的版本中,我们仍然可以通过AsynTask的executeOnExecutor方法并行执行任务
1.3源码分析
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
sDefaultExecutor串行的线程池
//executeOnExecutor //1
@MainThread
public final AsyncTask<Params, Progress, Result> 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;
}
//2
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
可以看到把Params封装成FutureTask(这个事并发类在这充当Runnable)对象
默认用的就是这个线程池
//3
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
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);
}
}
}
这时候就是把任务队列mTasks
scheduleNext()一个AsyncTask任务执行完后,调用这个来执行下一个AsyncTask
//4
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
由于FutureTask的run方法会调用mWorker的call方法最终会在线程池中执行,在这个方法中先将mTaskInvoked设为true,表示当前任务已经被调用过了,然后执行AsyncTask的doInBackgroud方法,接着传递给PostResult
AsyncTaks中有两个线程池
1.SerialExecutor
用于任务的队列
2.THREAD_POOL_EXECUTOR(也叫InternalHandler)
用于将执行环境从线程池切换到主线程
//5
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
//6
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
//7
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
可以看出sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程
这就要求1.sHandler这个对象必须在主线程中创建(在哪创建,handler里面的各种函数才能在哪执行,这里需要在主线程)----------->2.由于静态成员会在加载类的时候进行初始化,因此这就变相要求AsyncTask的类必须在主线程创建(因为sHandler是AsyncTask的静态成员变量),否则同一个进程中的AsyncTask都将无法正常工作
//8
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
1.4简单实验(证明AsyncTaks即可串行也是并行)
public class MainActivity extends Activity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_start_task).setOnClickListener(this);
}
@Override
public void onClick(View v) {
//串行
new MyAsyncTask("我是串行task1").execute();
// new MyAsyncTask("我是串行task2").execute();
// new MyAsyncTask("我是串行task3").execute();
// new MyAsyncTask("我是串行task4").execute();
// new MyAsyncTask("我是串行task5").execute();
// public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// return executeOnExecutor(sDefaultExecutor, params);
// }
//并行
new MyAsyncTask("我是并行task1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
new MyAsyncTask("我是并行task2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
new MyAsyncTask("我是并行task3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
new MyAsyncTask("我是并行task4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
new MyAsyncTask("我是并行task5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
}
private static class MyAsyncTask extends AsyncTask<String ,Integer,String>{
private String mName = "AsyncTask";
public MyAsyncTask(String mName) {
super();
this.mName = mName;
}
@Override
protected String doInBackground(String... params) {
SystemClock.sleep(3000);
return mName;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("xcqw "+mName+" execute finish at"+df.format(new Date()));
}
}
}
可以通过看打印得出既可以串行也可以并行,但是为什么呢?
串行调用execute和并行调用executeOnExecutor 最后都是调用 executeOnExecutor,只是传的参数不一样
//串行传的参数(默认参数)
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
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);
}
}
}
从队列中依次取出任务然后调用THREAD_POOL_EXECUTOR.execute(mActive);
//并行传的参数THREAD_POOL_EXECUTOR
每次都直接调用这个THREAD_POOL_EXECUTOR.execute,所以当然并行了
1.5简单实践
//版本更新功能用AsyncTask实现
//updateProgressDialogTask.java
package com.weixin.updateprogressdialog.task;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import com.weixin.updateprogressdialog.dialog.UpdateProcessDialog;
import com.weixin.updateprogressdialog.utils.ToastUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by xiongchao on 2015/10/29.
*/
public class UpdateTask extends AsyncTask<Object, Integer, File> {
//下载的路径
private String urlpath;
private UpdateProcessDialog mydialog;
private Handler threadhandler;
private Activity activity;
private FileOutputStream fos;
private BufferedInputStream bis;
private InputStream is;
//下载成功后重命名的文件
private String updateSuccessFilePath;
//下载过程中存放apk的地址
private String updatingStorePath;
//当前运行的线程
private UpdateTask mCurrentTaks;
public static boolean isStopDownload = false;
// public boolean isStopDownload() {
// return isStopDownload;
// }
//
// public void setIsStopDownload(boolean isStopDownload) {
// this.isStopDownload = isStopDownload;
// }
public void setUpdateComponents(UpdateTask Task,String serverversion,String updatingStorePath) {
this.mCurrentTaks = Task;
this.updateSuccessFilePath = Environment.getExternalStorageDirectory()+"/MyWeiXinUpDate/"+"update1"+serverversion+".apk";
this.updatingStorePath = updatingStorePath;
}
public UpdateTask(Activity activity,String urlpath, UpdateProcessDialog dialog,Handler threadhandler) {
this.activity = activity;
this.urlpath = urlpath;
this.mydialog = dialog;
this.threadhandler = threadhandler;
}
// 主线程运行, 预加载
@Override
protected void onPreExecute() {
super.onPreExecute();
}
// 子线程运行, 异步加载逻辑在此方法中处理
@Override
protected File doInBackground(Object... params) {
System.out.println("xcq " + "任务开始");
urlpath = (String) params[0];
//如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
try {
URL url = new URL(urlpath);
System.out.println("xcq " + "去请求连接");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置连接超时
conn.setConnectTimeout(5000);
//设置下载超时
conn.setReadTimeout(60000);
//是否连接成功//如果没有网络会在这里直接跳到异常
System.out.println("xcq " + "去请求响应码");
//响应码这阻塞时间较长,所以先打开dialog
threadhandler.post(new Runnable() {
@Override
public void run() {
System.out.println("xcq mydialog 3"+mydialog);
if(mydialog != null) {
mydialog.show();
}
}
});
int code = conn.getResponseCode();
if( 200 == code)
{
File file = new File(updatingStorePath);
File suceessFile = new File(updateSuccessFilePath);
//如果已经下载过直接去安装
if (suceessFile.exists()) {
return suceessFile;
}
//获取到文件的大小
long length = conn.getContentLength();
is = conn.getInputStream();
fos = new FileOutputStream(file);
bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len;
int total = 0;
boolean renameflag = false;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
total += len;
if (isStopDownload) {
stopDownLoad();
break;
}
int percent = (int) (total * 100 / length);
if(percent == 100){
System.out.println("xcq " + "下载成功");
//如果下载成功,下载文件重命名
renameflag = file.renameTo(suceessFile);
if(renameflag == false){
throw new Exception("文件重命名失败");
}
}
//获取当前下载量//进入progressupdate更新
publishProgress(percent);
}
fos.close();
bis.close();
is.close();
myDialogDismiss(mydialog);
if(mCurrentTaks != null && renameflag){
System.out.println("xcq " +"is"+isStopDownload);
return suceessFile;
}else{
//如果到这就是中断更新了//还有可能是下载成功后文件重命名失败
System.out.println("xcq " +"is"+isStopDownload);
return null;
}
}
else{
//连接服务器失败//服务器返回参数不是200(OK)
ToastUtils.show(activity, "连接服务器异常,请检查网络");
}
} catch (Exception e) {
System.out.println("xcq 异常" + e.toString());
try {if (fos != null){fos.close();}} catch (IOException e1) {e1.printStackTrace();}
try {if (bis != null) fos.close();} catch (IOException e1) {e1.printStackTrace();}
try {if (fos != null) is.close();} catch (IOException e1) {e1.printStackTrace();}
ToastUtils.show(activity,"下载失败,请检查网络");
stopDownLoad();
e.printStackTrace();
}
} else {
ToastUtils.show(activity,"请检查sd卡是否安装正确");
stopDownLoad();
return null;
}
return null;
}
// 主线程运行, 更新进度
@Override
protected void onProgressUpdate(Integer... values) {
int i = (int) values[0];
System.out.println("xcq Update进度" + i+"isStopDownload"+isStopDownload);
if (mydialog != null) {
mydialog.show();
mydialog.updateProgressAndTitle(i);
}
super.onProgressUpdate(values);
}
// 主线程运行, 更新主界面
@Override
protected void onPostExecute(File result) {
if (mCurrentTaks != null) {
if (result != null && !mCurrentTaks.isCancelled()) {
stopDownLoad();
Intent intent = new Intent();
//执行动作
intent.setAction(Intent.ACTION_VIEW);
//执行的数据类型
intent.setDataAndType(Uri.fromFile(result), "application/vnd.android.package-archive");
activity.startActivity(intent);
System.out.println("xcq onPostExecute");
}
}
stopDownLoad();
}
private void myDialogDismiss(AlertDialog dialog) {
if (dialog != null) {
dialog.dismiss();
dialog = null;
System.out.println("xcq dialog置null");
}
}
private void myTaskCancel() {
if (mCurrentTaks != null) {
mCurrentTaks.cancel(true);
mCurrentTaks = null;
}
}
private void stopDownLoad() {
myTaskCancel();
myDialogDismiss(mydialog);
isStopDownload = false;
}
}
//FirstActivity.java
public class FirstActivity extends Activity {
private UpdateProcessDialog mydialog;
private String serverVersion;
private UpdateTask task;
private String result = "自行添加下载地址";
private String updatestorepath = Environment.getExternalStorageDirectory()+"/MyWeiXinUpDate/update.apk";
private Handler threadhandler= null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
if(threadhandler == null){
threadhandler = new Handler();
}
}
public void update(View view) {
if (!UpdateTask.isStopDownload) {
isVersionsUpdate("1.1");
} else {
Toast.makeText(FirstActivity.this, "小点即可,切勿狂按", Toast.LENGTH_SHORT).show();
}
}
private void isVersionsUpdate(final String versions) {
try {
final JSONObject json = new JSONObject(result);
JSONObject requstResult = json.getJSONObject("RequstResult");
serverVersion = json.get("Versions").toString();
final String apkurl = json.getString("Download");
//这个state是从维信理财直接抄过来的
int state = requstResult.getInt("State");
if (state == 0) {
if (versions.compareTo(json.get("Versions").toString()) >= 0) {
Toast.makeText(FirstActivity.this, "已是最新版本", Toast.LENGTH_SHORT).show();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(FirstActivity.this);
builder.setTitle("有新版本" + json.get("Versions")
+ ",是否現在更新?");
builder.setPositiveButton("真的确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//开启asynctask下载
getApkFromServer(apkurl);
//download(apkurl);
}
});
builder.setNegativeButton("取消", null);
builder.create().show();
}
}
} catch (Exception e) {
System.out.println("xcq 异常11" + e.toString());
e.printStackTrace();
}
}
// 方法一
public void getApkFromServer(String url) {
mydialog = UpdateProcessDialog.showDeleteDialog(FirstActivity.this, 100, new UpdateProcessDialog.OnDeleteCancelListener() {
@Override
public void onCancel() {
UpdateTask.isStopDownload = true;
}
}, false);
//dialog一创建就show(为了初始化),所以这里就关闭显示
mydialog.dismiss();
task = new UpdateTask(FirstActivity.this,url, mydialog,threadhandler);
task.setUpdateComponents(task,serverVersion,updatestorepath);
task.execute(url);
}
2.HandlerThread
Thread(普通) run方法执行了一个耗时任务
HandlerThread内部创建了消息队列,外部需要通过Hanlder类的消息方式来通知他执行一个具体任务,由于HandlerThread的run方法是一个无限循环,因此当明确不需要再使用HandlerThread时,用quit或者quitSafely方法来终止线程的执行。
3.IntentService
1.在内部创建了一个线程执行耗时操,会在onHandlerIntent的回调方法中执行
2.执行完了会自动结束(onDestory),不需要手动操作
3. 开启多个会创建过个工作线程,但是每次只会执行一个工作线程,执行完第一个再执行第二个,然后才会结束(onDestory)
例子:
//MyIntentService.java
public class MyIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
//注意下这里!!!
public MyIntentService() {
super("MyIntentService");
}
@Override
public void onCreate() {
System.out.println("xcqw onCreate");
super.onCreate();
}
@Override
public void setIntentRedelivery(boolean enabled) {
System.out.println("xcqw setIntentRedelivery");
super.setIntentRedelivery(enabled);
}
@Override
public void onStart(Intent intent, int startId) {
System.out.println("xcqw onStart");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("xcqw onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
System.out.println("xcqw onHandleIntent");
//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
String action = intent.getExtras().getString("param");
if (action.equals("oper1")) {
System.out.println("Operation1");
}else if (action.equals("oper2")) {
System.out.println("Operation2");
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("xcqw onHandleIntent 结束了");
}
@Override
public void onDestroy() {
System.out.println("xcqw onDestroy");
super.onDestroy();
}
}
//MainActivity.java(开启两个不同的Service)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvNotice = (TextView) findViewById(R.id.tv_notice);
//可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个
//Operation 1
Intent startServiceIntent = new Intent(this, MyIntentService.class);
Bundle bundle = new Bundle();
bundle.putString("param", "oper1");
startServiceIntent.putExtras(bundle);
startService(startServiceIntent);
//Operation 2
Intent startServiceIntent2 = new Intent(this, MyIntentService.class);
Bundle bundle2 = new Bundle();
bundle2.putString("param", "oper2");
startServiceIntent2.putExtras(bundle2);
startService(startServiceIntent2);
}
}
//MainActivity.java(同一个Service开启两次)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvNotice = (TextView) findViewById(R.id.tv_notice);
//可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个
//Operation 1
Intent startServiceIntent = new Intent(this, MyIntentService.class);
Bundle bundle = new Bundle();
bundle.putString("param", "oper1");
startServiceIntent.putExtras(bundle);
System.out.println("xcqw 开启service");
startService(startServiceIntent);
System.out.println("xcqw 又开启了同一个service");
startService(startServiceIntent);
// //Operation 2
// Intent startServiceIntent2 = new Intent(this, MyIntentService.class);
// Bundle bundle2 = new Bundle();
// bundle2.putString("param", "oper2");
// startServiceIntent2.putExtras(bundle2);
// startService(startServiceIntent2);
}
}
结果
//开启不同的两个
xcqw 开启service one xcqw 开启service two xcqw onCreate xcqw onStartCommand xcqw onStart xcqw onStartCommand xcqw onStart xcqw onHandleIntent xcqw Operation1 xcqw onHandleIntent 结束了 xcqw onHandleIntent xcqw Operation2 xcqw onHandleIntent 结束了 xcqw onDestroy
//开启同一个两次
xcqw 开启service xcqw 又开启了同一个service xcqw onCreate xcqw onStartCommand xcqw onStart xcqw onHandleIntent xcqw onStartCommand xcqw onStart xcqw Operation1 xcqw onHandleIntent 结束了 xcqw onHandleIntent xcqw Operation1 xcqw onHandleIntent 结束了 xcqw onDestroy
三: Android线程池
线程池的优点
(1)重用线程池的线程,避免线程的创建和销毁所带来的性能开销
(2)可以控制线程池的最大并发数,避免大量的线程之间相互抢占系统资源而导致阻塞
(3)能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行
Android线程池的概念源于Java中的Executor,Executor是一个接口,Android中真正的线程池的实现为ThreadPoolExecutor,Android中的线程池都是直接或间接通过配置ThreadPoolExecutor来实现的.
1.5.1ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
corePoolSize :核心线程数,默认情况下,即使他们处于闲置状态(IDLE),核心线程也会在线程池中一直存活.
除非将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为True,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由KeepAliveTime所指定,超过这个时间核心线程就会被停止。
maximumPoolSize:线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务将会被阻塞。
keepAliveTime
非核心线程:超过这个时长,非核心线程就会被回收
核心线程(当ThreadPoolExecutor的allowThreadTimeOut属性设置为True才会受影响):影响上面有说
Unit:用于指定KeepAliveTime参数的时间单位
workQueue
线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数
中
threadFactory
线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口,他只有一个方法:Thread newThread(Runnable r)
defaultHandler:
当线程池无法执行新任务时,这可能是由于任务队列已满或者无法成功执行任务,有几个策略,默认是abortPolicy,用了这个就会直接抛异常
1.5.2ThreadpoolExecutor执行任务时大致遵循如下规则:
(1).如果线程池的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务
(2)如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会被插入任务队列中等待执行
(3)如果步骤2插入失败,这往往是任务队列满了,这个时候如果线程数量位达到线程池规定的最大值,那么会立即启动一个非核心线程来执行任务。
(4)如果步骤3的线程数量已经达到线程池规定的最大值,那么拒绝执行此任务,就会调用defaultHandler
哪些参数的配置在AsyncTask中可以清晰的看出来
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<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(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);
AsynTask对THREAD_POOL_EXECUTOR这个线程池进行了配置,配置后的线程池规格如下:
核心线程数等于:CPU核心数+1;
线程池的最大线程数为CPU核心数的2倍+1;
核心线程无超时机制,非核心线程在闲置时的超时时间为1秒
任务队列的容量为128
线程池的分类
这里指介绍Android中最常见的四类具有不同功能特性的线程池,它们都直接或间接地通过配置ThreadPoolExecutor来实现自己的功能特性,这四类线程池分别是FixedThreadPool,CachedThreadPool,ScheduledThreadPool以及SingleThreadExecutor.
1.FixedThreadPool
通过Executors的newFixedThreadPool方法来创建,它是一种线程数量固定的线程池,
当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。
当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。
由于FixedThreadPool只有核心线程并且这些核心线程不会被回收,这就意味着它能够更加快速地相应外界的请求。
newFixedThreadPool方法的实现如下,可以发现FixedThreadPool中只有核心线程并且这些核心线程没有超时机制,另外任务队列没有大小限制
核心线程超时机制:不会被回收
非核心线程在闲置时的超时时间:只有核心线程
任务队列的容量:无限制
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads,nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<Runnable>());
}
2.CachedThreadPool
通过Executor的new CachedThreadPool方法来创建
它是一种线程数量不定的线程池,只有非核心线程,并且其最大线程数为Interger.MAX_VALUE.由于Integer.MAX_VALUE是一个很大的数,实际上就相当于最大线程数可以任意大。
当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务。
线程中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收
和FixedThreadPool不同的是CachedThreadPool的任务队列其实相当于一个空集合,这就导致任何任务都会立即被执行。
因为在这种场景下SynchronousQueue是无法插入任务的,SynchronousQueue是一个非常特殊的队列,在很多情况下可以把它简单理解为一个无法存储元素的队列,由于它在实际中较少使用,这里就不深入探讨它了。
从CachedThreadPool的特性来看,这类线程池比较适合执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CacheThreadPool之中实际上是没有任何线程,它几乎是不占用任何系统资源的。
核心线程超时机制:只有非核心线程
线程池的最大线程数:Integer.MaxValue(也就相当于任意大)
非核心线程在闲置时的超时时间:60秒
任务队列的容量:无限制
public static ExecutorService newCachedThreadPool(int nThreads){
return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
3.ScheduledThreadPool
通过Executors 的newScheduledThreadPool方法来创建,它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收。ScheduledThreadPool这类线程池主要用于执行定时任务和具有固定周期的重复任务。newScheduledThreadPool方法的实现如下所示。
核心线程数:一个固定的值
线程池的最大线程数:Integer.MaxValue(也就相当于任意大)
非核心线程在闲置时的超时时间:立即回收
public static ExecutorService ScheduledThreadPool(int nThreads){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize,Integer.MAX_VALUE,0,NANOSECONDS,new DelayedWorkQueue());
}
4.singleThreadExecutor
通过Executors的newSingleThreadExecutor方法来创建。这类线程池内部只有一个核心线程,它确保所有任务都在同一个线程中按顺序执行。SingleThreadExecutor的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。实现方法如下
核心线程数:线程池中只有一个核心线程
public static ExecutorService newSingleThreadExecutor(int nThreads){
return new FinalizableDeleGatedExecutorService(new ThreadPoolExecutor(1,1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<Runnable>()));
}
以上是关于Android线程与线程池的主要内容,如果未能解决你的问题,请参考以下文章