android 艺术开发探索之线程和线程池
我记得不管是在学校的时候还是在社会面试的时候,我都很害怕别个问我关于线程的问题,因为我什么也不知道,别人问的时候总喜欢说,简单说一下你对线程的理解?如何处理并发问题啥的,一问我三不知,下面就来理解下关于线程的知识点。
线程定义
android线程分为主线程和子线程,一个进程只有一个主线程,其他都是子线程也叫作工作线程,主线程处理和ui相关的任务,子线程处理耗时操作,从android3.0开始系统要求网络 访问必须在子线程执行,否则会报NetWorkOnMainThreadException.在安卓中扮演线程的角色有Thread ,AsyncTask,IntentService,HandlerThread
1.AsyncTask
AsyncTask封装了线程池和Handler方便开发者在子线程更新ui, AsyncTask类必须在主线程中加载,他的对象必须在主线程中创建,execute方法必须在ui线程调用,不能在程序中直接 调用其OnpreExecute,onPostExecute,doInBackground和OnProgressUpdate,一个AsyncTask对象只能执行一次,即只
能调用一次execute方法,具体查看文章http://blog.csdn.net/u013200864/article/details/46792551
2. HandlerThread
Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了。如果此时我又有一个耗时任务需要执行,我们不得不重新创建线程去执行该耗时任务。然而,这样就存在一个性能问题:多次创建和销毁线程是很耗系统资源的所以使用HandlerThread。
HandlerThread是一个具有消息循环系统的线程,他的内部可以使用Handler,其继承了Thread,handler的工作是需要looper的,可以看我的这篇文章:http://blog.csdn.net/u013200864/article/details/52131675,所以说HandlerThread 只是一个线程里面获取了looper。并且默认创建好了handler的线程,省去了我们自己构建消息循环系统的步骤,和主线程的handler的原理一样,只是默认的Handler是调用的主线程的looper,而这个HandlerThread是子线程里面自己获取了looper构建了消息循环系统。IntentService内部采用 HandlerThread执行任务,任务完成自动退出,不容易被杀死。
public class MainActivity extends Activity {
HandlerThread handlerThread = new HandlerThread("张晓雅");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
Log.e("TAG", "thecurrent thread is" + Thread.currentThread());
try{
handlerThread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
super.handleMessage(msg);
}
};
for(int i = 0;i<5;i++){
handler.sendMessage(Message.obtain());
}
}
}
3. IntentService
IntentService是个抽象类继承了Service,只有实现子类才可以用它的特性,它类部有一个ServiceHandler继承了handler, start方法里面通过ServiceHandler发了一个消息,ServiceHandler类接收消息同时执行onHandleIntent抽象方法,stopSelf。oncreated中HandlerThread的looper传递给了ServiceHandler,所以我们实现onHandleIntent方法就好,通过如下方法启动:
Intent intent=new Intent();
intent.setClass(context, MyIntentService.class);
intent.putExtra(“task”, “task1”);//定时扫描的时间间隔
在MyIntentService里面实现onHandleIntent用switch来判断task是哪一个任务,然后做相应的耗时操作,当所有的耗时操作完成后他就会自己终止服务。 IntentService和一般的服务相比它会自己在耗时操作完成后自己终止,然后就是在它里面做耗时操作的时候不需要自己创建thread。
线程池
线程是操作系统最小单元,创建销毁都有相应开销,当有大量线程时,系统会用时间片轮转的方式调度每个线程,因此线 程无法做到绝对并行,当有大量线程时应采用线程池的方式,这样节省资源。
ThreadPoolExecutor类是线程池真正实现,构造器如下:
/**
* 创建一个线程池
*
* @param corePoolSize 线程池的核心线程数,即使处于空闲状态也会存活
* @param maximumPoolSize 池子里面能装的最大线程数,当活动线程数到达这个数值后,后续新的任务会阻塞
* @param keepAliveTime当allowCoreThreadTimeOut设为true的时候,keepAliveTime也会作用于核心线程的超时策略
* 当其不为true的时候是指非核心线程闲置的时长,超过这个时间都会被回收
* @param unit ,keepAliveTime时间的单位,枚举,有秒,毫秒,分钟
* @param workQueue 线程池的任务队列,通过execute方法提交的Runable会存储在这个参数中
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
android中的线程池分为4类
Runnable mRunnable=new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
}
};
// 建立一个容量为3的固定尺寸的线程池,只有核心线程,无超时设置,线程数量固定,线程池关闭后才会回收,它能够更加快速地响应外界请求
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
newFixedThreadPool.execute(mRunnable);
//线程数量不固定的线程池,只有非核心线程,最大线程数为Integer.MaxValue,有空闲的就用空闲的, 没空闲的就创建新线程,闲置线程的超时时间为60秒,任何任务都会被立即执行,这类线程池比较适合执行大量耗时较少的任务,它几乎是不占用任何系统资源的
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(mRunnable);
//它的核心线程数固定,而非核心线程数没有限制,并且当非核心线程闲置时会被立即回收,主要用于执行定时任务和具有固定周期的重复任务
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(4);
//2000MS后执行
newScheduledThreadPool.schedule(mRunnable,2000,TimeUnit.MILLISECONDS);
//延迟10ms后,每隔1000ms执行一次mRunnable
newScheduledThreadPool.scheduleAtFixedRate(mRunnable,10,1000,TimeUnit.MILLISECONDS);
//内部只有一个核心线程,他确保所有的任务都在同一个线程中按顺序执行,无需处理线程同步问题
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(mRunnable);