多线程基础
多线程基础
AsyncTask
执行流程
new AsyncTask()
Copy public AsyncTask() {
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) ;
}
};
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 ) ;
}
}
};
}
会初始化一个Callable和一个FutureTask,当然Callable是要被传到FutureTask的构造方法中去的,最终线程池执行的FutureTask,这两个都是成员变量。
在Callable中可以看到:Result result = doInBackground(mParams); 然后在FutureTask中它有一个执行完成的回调方法done()
之所以用FutureTask就是因为它是负责执行多线程可以返回执行结果的。
然后:
Copy private Result postResult( Result result) {
@ SuppressWarnings ( "unchecked" )
Message message = getHandler() . obtainMessage (MESSAGE_POST_RESULT ,
new AsyncTaskResult < Result >( this , result));
message . sendToTarget ();
return result;
}
在这里面,它就是把执行的结果给发到主线程,里面有当前AsyncTask引用和result对象。
Copy protected final void publishProgress( Progress ... values ) {
if ( ! isCancelled() ) {
getHandler() . obtainMessage (MESSAGE_POST_PROGRESS ,
new AsyncTaskResult < Progress >( this , values)) . sendToTarget ();
}
}
这个是因为在doBackground中去调用publishProgress(Progress... values),然后可以在主线程中接收到它的处理逻辑。
Copy 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 ;
}
}
}
所有任务都是最后由它来分发执行的。
最后关键的来了,最后肯定是要调用执行的
Copy public final AsyncTask< Params , Progress , Result > execute( Params ... params ) {
return executeOnExecutor(sDefaultExecutor , params) ;
}
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 ;
}
重点看下:
Copy exec . execute (mFuture);
我们看下sDefaultExecutor是个什么东西
Copy 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);
}
}
}
也就是说exec.execute(mFuture);这句话会调用SerialExecutor的方法,每次调用execute都会把futureTask给加进去,然后放到一个双端队列里面,如果当前没有执行的Runnable就从队列中取出一个任务去执行,如果有任务的话,那么就只是先单纯的加到队列里,并不会执行。因为每次执行完一个Runnable后,它有一个finally方法,最后一次会再次调用scheduleNext方法,然后再从队列中去取出一个任务去执行,当然前提是队列不能为空,所以,它的逻辑是其实是执行一个任务结束后,然后就去队列里去取任务,如果有就放到线程池里去执行,就是这么简单。所以它是串行的。它是通过先把任务缓存到一个队列里,然后执行完一个就从队列中取出一个放到线程池中去执行,也就是说,队列里有多个任务,但是,线程池始终只有一个任务。
不过线程的无界队列 new LinkedBlockingQueue(128)这个128有点让人恍惚,其实它是指如果你配置成多线程并行的情况下,缓冲队列最多有128个,否则就执行Reject策略(默认是AbortPolicy)。
我们再来看下配置线程池的相关代码
Copy public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE , MAXIMUM_POOL_SIZE , KEEP_ALIVE ,
TimeUnit . SECONDS , sPoolWorkQueue , sThreadFactory) ;
CORE_POOL_SIZE 核心线程数 MAXIMUM_POOL_SIZE 最大线程数量 KEEP_ALIVE 1s闲置回收 TimeUnit.SECONDS 时间单位 sPoolWorkQueue 异步任务队列 sThreadFactory 线程工厂
关于线程池,先会把CORE_POOL_SIZE这个填满,填满之后,再往缓存队列里放,缓存队列也满了,就增加线程,直到增加到MAXIMUM_POOL_SIZE,然后如果再有新的任务,那么 就只能执行拒绝策略了。
如果你自己配置一个无界队列,那么 任务就随便放了直到把系统干爆为止。
Copy private void startDownload() {
for ( int i = 0 ; i < 200 ; i ++ ) {
new DownloadTask() . execute ();
}
}
private AtomicInteger mAtomicInteger = new AtomicInteger( 0 ) ;
class DownloadTask extends AsyncTask < Void , Integer , Boolean > {
@ Override
protected void onPreExecute () {
}
@ Override
protected Boolean doInBackground ( Void ... params) {
try {
Thread . sleep ( 1000 );
} catch ( InterruptedException e) {
e . printStackTrace ();
}
System . out . println ( mAtomicInteger . incrementAndGet ());
return true ;
}
@ Override
protected void onProgressUpdate ( Integer ... values) {
}
@ Override
protected void onPostExecute ( Boolean result) {
}
}
上面的代码是每隔1s打印一次,你一次new出来200个也不是说都把放到线程池中的BlockingQueue中,而是放到Executor中的ArrayDeque这个是会不断扩容的队列,明白了吧。
AsyncTask有什么缺点:
内存泄露 — 这是因为匿名内部类持有外部类的引用,所以如果子线程没有执行完毕,
线程池容量不够抛出异常。这个异常其实基本不会出现,因为默认情况下是串行的,而且如果你要自定义线程池的话,可以设置一个更大的BlockingQueue啊。所以这点基本不存在。
Android AsyncTask完全解析,带你从源码的角度彻底理解
HandlerThread
HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.
Copy import android . os . Bundle ;
import android . os . Handler ;
import android . os . HandlerThread ;
import android . os . Message ;
import android . support . v7 . app . AppCompatActivity ;
import android . util . Log ;
public class MainActivity extends AppCompatActivity {
private HandlerThread myHandlerThread ;
private Handler handler ;
@ Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate (savedInstanceState);
setContentView( R . layout . activity_main ) ;
//创建一个线程,线程名字:handler-thread
myHandlerThread = new HandlerThread( "handler-thread" ) ;
//开启一个线程
myHandlerThread . start ();
//在这个线程中创建一个handler对象
handler = new Handler( myHandlerThread . getLooper() ) {
@ Override
public void handleMessage ( Message msg) {
super . handleMessage (msg);
//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作
Log . d ( "handler " , "消息: " + msg . what + " 线程: " + Thread . currentThread () . getName () ) ;
}
};
//在主线程给handler发送消息
handler . sendEmptyMessage ( 1 ) ;
new Thread( new Runnable() {
@ Override
public void run() {
//在子线程给handler发送数据
handler . sendEmptyMessage( 2 ) ;
}
}) . start () ;
}
@ Override
protected void onDestroy () {
super . onDestroy ();
//释放资源
myHandlerThread . quit () ;
}
}
Copy / com . app D / handler : 消息: 1 线程: handler - thread
/ com . app D / handler : 消息: 2 线程: handler - thread
HandlerThread的特点:
HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅 。
开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的 。
但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理 。
HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程 。
对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。
IntentService
IntentService内部会创建一个HandlerThread,onHandleIntent在HandlerThread线程中执行
IntentService源码:
Copy @ Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super . onCreate ();
HandlerThread thread = new HandlerThread( "IntentService[" + mName + "]" ) ;
thread . start ();
mServiceLooper = thread . getLooper ();
mServiceHandler = new ServiceHandler(mServiceLooper) ;
}
@ Override
public void onStart( Intent intent , int startId) {
Message msg = mServiceHandler . obtainMessage ();
msg . arg1 = startId;
msg . obj = intent;
mServiceHandler . sendMessage (msg);
}
private final class ServiceHandler extends Handler {
public ServiceHandler ( Looper looper) {
super(looper);
}
@ Override
public void handleMessage ( Message msg) {
onHandleIntent((Intent) msg . obj ) ;
stopSelf( msg . arg1 ) ;
}
}
protected abstract void onHandleIntent( Intent intent) ;
看明白了吧,在onCreate中去初始化HandlerThread和用HandlerThread的Looper初始化的Handler,在onStart中发送消息,在handlerMessage中去调用onHandleIntent,然后我们重写onHandleIntent方法即可。
IntentService(本质:Service+HandlerThread+Intent) startService 至少要有一个空的构造方法
优点
它有一个很大的缺点就是,它无法直接和主线程进行通信,其实很多业务是后台做完请求之后要在UI上更新,其实它无法实现,虽然可以用消息机制通信 。
Loader
在 Android 配备的几大异步利器中,Loader 是3.0之后才出现的,主要为了方便在 Activity 和 Fragment 中异步加载数据。它有如下的特点:
每个Activity 和 Fragment 都可以使用 (3.0之前可以使用 support-lib)
监视数据源,如果数据发生变化了,会自动传回更新后的结果
如果被重新创建(比如屏幕选装)了会自动连接到上次的Cursor,这样不需要重新查询数据
上面说过了,Android提供了很多后台任务的机制,不过除了AsyncTask,无法把后台执行的结果给调用者(当然FutureTask可以,AsyncTask也是这样做的),还有一个就是Loader可以在后台加载数据,然后和调用者通信。
Loader保证子线程与Activity或者Fragment的生命周期一致 Activity和Fragment自带LoaderManager
优点: 1.方便 2.Activity或者Fragment的生命周期一致 3.数据缓存与更新通知
Activity中启动子线程的缺点
Copy import android . app . Activity ;
import android . app . LoaderManager ;
import android . content . CursorLoader ;
import android . content . Loader ;
import android . database . Cursor ;
import android . os . Bundle ;
import android . provider . CallLog ;
import android . util . Log ;
import android . widget . ListView ;
public class MainActivity extends Activity {
private static final String TAG = "jason" ;
// 查询指定的条目
private static final String [] CALLLOG_PROJECTION = new String [] { CallLog . Calls . _ID , CallLog . Calls . NUMBER ,
CallLog . Calls . CACHED_NAME , CallLog . Calls . TYPE , CallLog . Calls . DATE };
private ListView mListView;
private MyLoaderCallback mLoaderCallback = new MyLoaderCallback() ;
private MyCursorAdapter mAdapter;
@ Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate (savedInstanceState);
setContentView( R . layout . activity_main ) ;
mListView = (ListView) findViewById( R . id . lv_list ) ;
mAdapter = new MyCursorAdapter( MainActivity . this , null ) ;
mListView . setAdapter (mAdapter);
//执行Loader的回调
getLoaderManager() . initLoader ( 0 , null , mLoaderCallback);
}
private class MyLoaderCallback implements LoaderManager . LoaderCallbacks < Cursor > {
//创建Loader
@ Override
public Loader < Cursor > onCreateLoader ( int id , Bundle args) {
//加载的过程在子线程中进行
CursorLoader loader = new CursorLoader( MainActivity . this , CallLog . Calls . CONTENT_URI , CALLLOG_PROJECTION ,
null , null , CallLog . Calls . DEFAULT_SORT_ORDER ) ;
Log . d (TAG , "onCreateLoader" );
return loader;
}
//Loader检测底层数据,当检测到改变时,自动执行新的载入获取最新数据
//Activity/Fragment所需要做的就是初始化Loader,并且对任何反馈回来的数据进行响应。
@ Override
public void onLoadFinished ( Loader < Cursor > loader , Cursor data) {
if (data == null )
return ;
mAdapter . swapCursor (data);
Log . d (TAG , "onLoadFinished data count = " + data . getCount ());
}
//OnDestroy,自动停止load
@ Override
public void onLoaderReset ( Loader < Cursor > loader) {
Log . d (TAG , "onLoaderReset" );
mAdapter . swapCursor ( null );
}
}
}
其实Loader后台的执行是靠AsyncTask 。
Android之Loader介绍