Android的线程和线程池

首先先分享一个小的知识点,如何让edittext在没有点击之前不显示光标?

很多人都会用textIn.clearFocus();但是有时候会发现它是没有作用的,找了找发现clearFocus()并不是edittext的方法而是它父类的父类view中的方法。看了看源码大致就是说如果你使用了这个方法,它会从整个布局的顶部去找一个需要焦点的控件将焦点给它。本人英语比较渣,自己翻译理解就是这样的,不过也比较合理啊,要不然为什么当我们使用了这个方法有时候不起作用呢,这就是因为它的顶部不是一个那么需要获得焦点的控件,因此焦点又被分配到它这里了,这里面是有级别区分的。那么怎样才能让它先不要获得焦点呢。方法一:重写edittext,当然就是重写父类的clearFocus()的方法,在方法里让它失去焦点。并且点击才可以获得焦点。当然我自己也觉得比较麻烦,那么就建议大家使用方法二:在editext的外面包裹的控件例如LinearLayout什么的添加下面两句就可以啦,意思就是焦点是我的,嘿嘿


 android:focusable="true"  

 android:focusableInTouchMode="true"

 

现在要进入今天的正题了。这里要讲的是Android的线程与线程池,那么除了传统的Thread以外,还包含AsyncTask,HandlerThread、以及IntentService,这三者的底层实现也是线程。
 

1.  new Thread 

 

[java] view plain copy  print?在CODE上查看代码片派生到我的代码片

  1. new Thread(new Runnable() {      
  2.     @Override    
  3.     public void run() {    
  4.         // TODO Auto-generated method stub    
  5.     }    
  6. }).start();    
  7.  

 

这是最基本的开启线程的方式(实现Runnable接口),我们在初学安卓或者早期开发安卓的开发者们都是用这种方法去开启线程的,此外还有两种方式去开启线程:继承Thread类重写run()方法 和 实现Callable接口,重写 call()方法,这里就不做介绍了。

但是上面的三种开启线程的方法在我们编写android应用时会有以下的弊端:

1.但是我们都知道java线程机制是抢占性质的,调度机会中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使得每个线程都会分配合理的时间去驱动它的任务,java提供了改变线程优先级的方法,但是这会非常难以维护,试图去操纵线程优先级通常是错误的。

2. 每次开启线程创建Thread,销毁线程性能会是很差的

3 .而且这三种开启线程的方法缺乏更多功能,如定时执行、定期执行、线程中断。

我们在写程序时如果是开启线程数量比较少时确实可以用这种方法,但是如果有很多开启线程的操作的话就不建议这么做了。

 

2、Java 线程池

 

Java通过Executors提供四种线程池,分别为:
CachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。在线程空闲60秒后终止线程。
FixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
SingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

Executors类用于管理Thread对象,简化并发过程,我们可以看到FixedThreadPool的创建过程:

[html] view plain copy  print?在CODE上查看代码片派生到我的代码片

  1. public static ExecutorService newFixedThreadPool(int nThreads) {    
  2. return new ThreadPoolExecutor(nThreads, nThreads,     
  3.                                  0L, TimeUnit.MILLISECONDS,    
  4.                                   new LinkedBlockingQueue<Runnable>());    
  5. }    

显然这四种线程池方法都是返回实现了ExecutorService接口的ThreadPoolExecutor。当然我们也可以直接用ThreadPoolExecutor来自定义更灵活的线程池。

 

我们先看看ThreadPoolExecutor的构建参数:

[java] view plain copy  print?在CODE上查看代码片派生到我的代码片

  1. public ThreadPoolExecutor(int corePoolSize,    
  2.                          int maximumPoolSize,    
  3.                         long keepAliveTime,    
  4.                         TimeUnit unit,    
  5.                          BlockingQueue<Runnable> workQueue,    
  6.                         ThreadFactory threadFactory,    
  7.                           RejectedExecutionHandler handler)   

当池子大小小于corePoolSize就新建线程,并处理请求,当池子大小大于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理,当workQueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理。另外,当池子的线程数大于corePoolSize的时候,多余的线程会等待keepAliveTime长的时间,如果无请求可处理就自行销毁


 接下来我们来看看CachedThreadPool:

[java] view plain copy  print?在CODE上查看代码片派生到我的代码片

  1. public static ExecutorService newCachedThreadPool() {    
  2.     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,    
  3.                                  60L, TimeUnit.SECONDS,    
  4.                                   new SynchronousQueue<Runnable>());    
  5. }    

CachedThreadPool在程序执行时会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此是Executor的首选,只有当这种方式会引发问题,或者不符合业务需要时才采用另外的三种Executor提供的线程池

SingleThreadExecutor 就是线程数量为1的FixedThreadPool,如果向SingleThreadExecutor提交多个任务,那么这些任务会排队,每个任务都会在下个任务开始之前就结束,所有任务都用一个线程,并且按照提交的顺序执行。

 线程池用于线程数量比较多时的场景,如果只开启2,3个线程就用线程池,显然会极度的浪费资源

 

补充:AsyncTask

从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI

但是,AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。

AsyncTask是一个抽象的泛型类,它提供了Params、Progress、和Result这三个泛型参数,

其中Params表示参数的类型,Progress表示后台任务的执行进度的类型,而Result则表示后台任务的返回结果的类型。

如果不需要传递具体的参数,那么这三个泛型参数可以用Void来代替。

onPreExecute() 在主线程中执行,在异步任务执行之前。一般可以用于一些准备工作

doInBackground(Params... params),在线程池中执行,此方法可用于执行异步任务,params参数表示异步任务的输入参数。

onProgressUpdate(Progress...values),在主线程中执行,当后台任务的执行进度发生改变时会调用

onPostExecute(Result result),在主线程中执行,在异步任务执行之后,此方法会调用,result参数是后台任务的返回值。
 

此外还提供了onCancelled()方法,同样在主线程中执行,当异步任务被取消,onCancelled()方法会被调用,这个时候onPostExecute则不会被调用。

AsyncTask在具体的使用过程中也是有 一些条件限制的,主要有:

AsyncTask的类必须在主线程中加载,这就意味着第一次访问AsyncTask必须发生在主线程中,当然这个过程在Android4.1及以上版本中已经被系统自动完成。
 

Android5.0中,ActivityThread的main方法中,它会调用AsyncTask的init方法,这就满足了AsyncTask的类必须在主线程中进行加载这个条件了。

AsyncTask的对象必须在主线程中创建

execute方法必须在UI线程调用

不要在程序中直接调用onPreExecute()、onPostExecute()、doInBackground和onProgressUpdate方法

一个AsyncTask对象只能执行一次,即只能调用一次execute方法

在Android1.6之前,AsyncTask是串行执行任务的,Android1.6的时候开始采用线程池处理并行任务,

但是从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务,

尽管如此,在Android3.0及之后的版本中,我们仍可以通过AsyncTask的executeOnExecutor方法来并行地执行任务。

 

          下班啦!大家拜拜啦!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值