您现在的位置是:首页 > 正文

Android中线程和线程池

2024-02-01 05:52:36阅读 3

我们知道线程是CPU调度的最小单位。在Android中主线程是不能够做耗时操作的,子线程是不能够更新UI的。在Android中,除了Thread外,扮演线程的角色有很多,如AsyncTask,IntentService和HandlerThread等等。由于内容过多,所以将分为上下两部分,第一部分主要和大家谈谈Android中的线程,以及在Android中的常用的线程池。第二部分我们一起来了解一下AsyncTask的使用和工作原理。

 

1、HandlerThread

HandlerThread是Thread的子类,它是一种可以使用Handler的Thread,它的实现比较简单。我们来看看它的源码:

 1 package android.os;
 2 
 3 public class HandlerThread extends Thread {
 4     int mPriority;
 5     int mTid = -1;
 6     Looper mLooper;
 7 
 8     public HandlerThread(String name) {
 9         super(name);
10         mPriority = Process.THREAD_PRIORITY_DEFAULT;
11     }
12     
13 
14       public HandlerThread(String name, int priority) {
15         super(name);
16         mPriority = priority;
17     }
18     
19 
20        protected void onLooperPrepared() {
21     }
22 
23 
24 
25     @Override
26     public void run() {
27         mTid = Process.myTid();
28         Looper.prepare();
29         synchronized (this) {
30             mLooper = Looper.myLooper();
31             notifyAll();
32         }
33         Process.setThreadPriority(mPriority);
34         onLooperPrepared();
35         Looper.loop();
36         mTid = -1;
37     }
38     
39 
40 
41      public Looper getLooper() {
42         if (!isAlive()) {
43             return null;
44         }
45         
46         // If the thread has been started, wait until the looper has been created.
47         synchronized (this) {
48             while (isAlive() && mLooper == null) {
49                 try {
50                     wait();
51                 } catch (InterruptedException e) {
52                 }
53             }
54         }
55         return mLooper;
56     }
57 
58 
59 
60        public boolean quit() {
61         Looper looper = getLooper();
62         if (looper != null) {
63             looper.quit();
64             return true;
65         }
66         return false;
67     }
68 
69 
70 
71 
72 
73       public boolean quitSafely() {
74         Looper looper = getLooper();
75         if (looper != null) {
76             looper.quitSafely();
77             return true;
78         }
79         return false;
80     }
81 
82 
83 
84 
85      public int getThreadId() {
86         return mTid;
87     }
88 }

为了让大家看清楚,我们源码的一些英文注释干掉了,现在就很清晰了。整个类中,除了构造方法和对外提供几个public方法以外,就剩一个方法了run()。从它的实现来看,和普通的Thread实现没有什么区别。都是在run()方法中执行耗时操作。不过,HandlerThread内部创建了消息队列,并且run()方法是一个无限循环的方法,当我们不需要HandlerThread的时候,我们可以调用quitSafely()或者quit()方法来结束这个线程。这是比较方便的。

 

 

2、IntentService

IntentService是一种特殊的Service,它是Service的子类,并且它是一个抽象类,所以必须创建它的子类才可以使用Intent Service。Intent Service可用于执行后台的耗时任务,当任务执行完毕,它会自己结束,不需要开发着手动结束它。这里需要注意一个问题,Intentservice内置有线程,但是它还是属于Service,所以它的优先级会比线程高很多,所以不容易被系统杀死。所以比较合适去执行一些优先级比较高的任务。看看它的源码:

  1 package android.app;
  2 
  3 import android.annotation.WorkerThread;
  4 import android.annotation.Nullable;
  5 import android.content.Intent;
  6 import android.os.Handler;
  7 import android.os.HandlerThread;
  8 import android.os.IBinder;
  9 import android.os.Looper;
 10 import android.os.Message;
 11 
 12 
 13 
 14 public abstract class IntentService extends Service {
 15     private volatile Looper mServiceLooper;
 16     private volatile ServiceHandler mServiceHandler;
 17     private String mName;
 18     private boolean mRedelivery;
 19 
 20 
 21 
 22     private final class ServiceHandler extends Handler {
 23         public ServiceHandler(Looper looper) {
 24             super(looper);
 25         }
 26 
 27 
 28 
 29         @Override
 30         public void handleMessage(Message msg) {
 31             onHandleIntent((Intent)msg.obj);
 32             stopSelf(msg.arg1);
 33         }
 34     }
 35 
 36 
 37 
 38 
 39     public IntentService(String name) {
 40         super();
 41         mName = name;
 42     }
 43 
 44 
 45 
 46 
 47    public void setIntentRedelivery(boolean enabled) {
 48         mRedelivery = enabled;
 49     }
 50 
 51     @Override
 52     public void onCreate() {
 53         // TODO: It would be nice to have an option to hold a partial wakelock
 54         // during processing, and to have a static startService(Context, Intent)
 55         // method that would launch the service & hand off a wakelock.
 56 
 57         super.onCreate();
 58         HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
 59         thread.start();
 60 
 61         mServiceLooper = thread.getLooper();
 62         mServiceHandler = new ServiceHandler(mServiceLooper);
 63     }
 64 
 65 
 66 
 67 
 68     @Override
 69     public void onStart(@Nullable Intent intent, int startId) {
 70         Message msg = mServiceHandler.obtainMessage();
 71         msg.arg1 = startId;
 72         msg.obj = intent;
 73         mServiceHandler.sendMessage(msg);
 74     }
 75 
 76 
 77 
 78 
 79       @Override
 80     public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
 81         onStart(intent, startId);
 82         return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
 83     }
 84 
 85 
 86 
 87 
 88     @Override
 89     public void onDestroy() {
 90         mServiceLooper.quit();
 91     }
 92 
 93 
 94 
 95 
 96     public IBinder onBind(Intent intent) {
 97         return null;
 98     }
 99 
100 
101 
102 
103     @WorkerThread
104     protected abstract void onHandleIntent(@Nullable Intent intent);
105 }

这里就很简单了,这些方法对于经常使用Service的朋友来说,就很熟悉了。大家看onCreate()方法。没错IntentService就是封装了HandlerThread和Handler。

当我们启动IntentService是onCreate(),方法将会被调用,然后就会创建HandlerThread和ServiceHandler。而onStartCommand()方法又调用了onStart()方法,从onStart()方法可以看出IntentService 仅仅是通过ServiceHandler来发一个消息,这个消息会在HandlerThread中被处理掉。

大家看这个onStart()方法,将intent作为消息传递给onHandleIntent,这个intent通常是我们传递进来的数据。而onHandleIntent就是通过这个intent来区别具体的后台任务的。 

 

好了,AsyncTask的使用和工作原理。我们会在下一章在说。下面我们看看线程池吧。

不知道大家有没有遇到过这种情况。我们在写项目,遇到耗时操作的时候,怎么办呢,是不是new Thread().start,那这样的话,整个项目中得new多少个Thread。这种明显是很浪费性能。毕竟线程也是好资源的嘛。那么有没有一种可以方法对线程进行复用呢?答案就是线程池。

 

先说一下线程池的好处:

1、重用线程池中的线程,避免因为线程的创建和销毁带来的性能开销。

2、能有效的控制线程池中的线程并发数,避免大量线程之间因为互相抢占资源而导致的阻塞现象。

3、能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

 

ThreadPoolExecutor

Android中的线程池概念是来源于java中Executor,Executor是一个空的接口,真正的线程池实现ThreadPoolExecutor。

1 public ThreadPoolExecutor(int corePoolSize,
2                               int maximumPoolSize,
3                               long keepAliveTime,
4                               TimeUnit unit,
5                               BlockingQueue<Runnable> workQueue,
6                               ThreadFactory threadFactory) {
7         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
8              threadFactory, defaultHandler);
9     }

简单介绍一下ThreadPoolExcutor各个参数的含义

corePoolSize:线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态。当我们把ThreadPoolExecutor中的allowCoreThreadTimeOut属性设置为true,那么闲置的核心线程在等待新任务的时候,如果时间超过keepAliveTime所设置的时间,核心线程将会被回收。

maximumPoolSize:设置最大线程池能够容纳的最大线程数,当线程池中的线程达到这个数以后,新任务将会被阻塞。

 

keepAliveTime:非核心线程数闲置的时间。

unit:指定keepAliveTime参数的时间单位。

workQueue:线程池中的任务队列。

threadFactory:线程工厂,为线程池提供创建新线程的功能。

 

 

线程池的分类

Android中常见的线程池有四种,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。

 

FixedThreadPool

FixedThreadPool线程池是通过Executors的new FixedThreadPool方法来创建。它的特点是该线程池中的线程数量是固定的。即使线程处于闲置的状态,它们也不会被回收,除非线程池被关闭。当所有的线程都处于活跃状态的时候,新任务就处于队列中等待线程来处理。注意,FixedThreadPool只有核心线程,没有非核心线程。

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

 

 

CachedThreadPool

CachedThreadPool线程池是通过Executors的newCachedThreadPool进行创建的。它是一种线程数目不固定的线程池,它没有核心线程,只有非核心线程,当线程池中的线程都处于活跃状态,就会创建新的线程来处理新的任务。否则就会利用闲置的线程来处理新的任务。线程池中的线程都有超时机制,这个超时机制时长是60s,超过这个时间,闲置的线程就会被回收。这种线程池适合处理大量并且耗时较少的任务。这里得说一下,CachedThreadPool的任务队列,基本都是空的。

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

 

ScheduledThreadPool

ScheduledThreadPool线程池是通过Executors的newScheduledThreadPool进行创建的,它的核心线程是固定的,但是非核心线程数是不固定的,并且当非核心线程一处于空闲状态,就立即被回收。这种线程适合执行定时任务和具有固定周期的重复任务。

 1 public static ScheduledExecutorService newScheduledThreadPool(
 2             int corePoolSize, ThreadFactory threadFactory) {
 3         return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
 4     }
 5 
 6 
 7 public ScheduledThreadPoolExecutor(int corePoolSize,
 8                                        ThreadFactory threadFactory) {
 9         super(corePoolSize, Integer.MAX_VALUE,
10               DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
11               new DelayedWorkQueue(), threadFactory);
12     }

 

SingleThreadExecutor

SingleThreadExecutor线程池是通过Executors的newSingleThreadExecutor方法来创建的,这类线程池中只有一个核心线程,也没有非核心线程,这就确保了所有任务能够在同一个线程并且按照顺序来执行,这样就不需要考虑线程同步的问题。

 

 1 public static ExecutorService newSingleThreadExecutor() {
 2 
 3         return new FinalizableDelegatedExecutorService
 4 
 5             (new ThreadPoolExecutor(1, 1,
 6 
 7                                     0L, TimeUnit.MILLISECONDS,
 8 
 9                                     new LinkedBlockingQueue<Runnable>()));
10 
11     }

 

好了,写了这么多,真特么累,下部分就和大家分享一下AsyncTask的 工作原理。

 

转载于:https://www.cnblogs.com/huangjialin/p/8546513.html

网站文章

  • Cmake一次编译多个cpp

    Module下有一个CMakeLists.txt 的文件 默认内容是这样的,(只贴了需要改动的部分)cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC# or SHARED, and provides the relative paths...

    2024-02-01 05:52:07
  • jvm原理(18)类加载器命名空间总结与扩展类加载器要点分析

    jvm原理(18)类加载器命名空间总结与扩展类加载器要点分析

    类加载双亲委托模型的好处: 1、可以确保Java核心库的类型安全:所有的Java应用都至少会引用Java.lang.Object类,也就是说在运行期,java.lang.Object这个类会被加载到J...

    2024-02-01 05:52:01
  • win系统下64位Julia链接fortran的方法

    win系统下64位Julia链接fortran的方法

    综合网络上各位大佬的方法,实现了在win系统下64位Julia链接fortran的方法。

    2024-02-01 05:51:55
  • 堆

    一.堆的定义堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组对象。二.API设计三.代码实现public class Heap<T extends Comparable...

    2024-02-01 05:51:26
  • 你的网卡真有千兆么?——千兆网卡传输速度解析 热门推荐

    随着PS3it技术的破解和可以利用电脑FTP向PS3传送文件,千兆网卡成为了不少玩家必备的工具。要知道PS3it技术本身自带千兆网卡,如果利用FTP软件以及电脑上的千兆网卡进行文件传输,其速度远比采用...

    2024-02-01 05:51:19
  • JavaScript Equality Table

    JavaScript Equality Table

    Tables displaying the issue: and == Moral of the story use ===

    2024-02-01 05:51:13
  • Autoware pure_pursuit节点适配差速底盘

    Autoware pure_pursuit节点适配差速底盘

    Autoware pure_pursuit节点输出的话题是 "/twist_raw", 需要转换为我们小车底盘控制速度的话题,我这里直接用"/cmd_vel"。主要任务是消息格式的转换,下面详细介绍。...

    2024-02-01 05:50:44
  • 调用API

    3.编写API请求:编写代码向API发送请求,包括所需参数和API密钥等。使用最常见的请求方法是HTTP请求,包括GET、POST、PUT、DELETE等。4.解析API响应:API会返回响应数据,需...

    2024-02-01 05:50:30
  • Codeforces 1221E. Game With String

    传送门首先每一段连续的 $...$ 都是互不影响的,所以可以一段段考虑考虑最简单的情况,此时每一段都大于等于 $a$ 并且小于 $2b$ ,那么每一段都只能放一次,胜负直接根据段数即可得到答案考虑如果存在段长小于 $a$ 却大于等于 $b$ 的情况,此时后手可以随时放在那个位置,当然也可以不放,这样胜负就被掌握在后手手里(他可以随时选择交换先后手)所以对于上面那一种情况,...

    2024-02-01 05:50:23
  • spring boot 整合sharding jdbc 遇到的一些问题以及实例源码

    spring boot 整合sharding jdbc 遇到的一些问题以及实例源码

    文章目录一、整合1.pom.xml 新增依赖(这里默认你项目中已经有了Mysql的依赖)2.配置3.遇到的问题“The bean 'dataSource', defined in class path...

    2024-02-01 05:49:55