• Android 线程和线程池核心技术-走进线程世界 (一)


    🔥 走进线程世界 🔥

            安卓应用在运行时必然存在一个进程 , 进程中必然会存在一个线程 (我们称之为UI线程)。线程可以看着是进程的实体 , 也是CPU调度的基本单位 , 也是比较进程更小的独立运行的基本单位 。安卓中的线程可以分为两类 : 一类是UI线程 , 另外一类是工作线程 。引用工作线程的原因 : UI线程都是用来更新UI控件的 , 耗时任务也在UI线程中来执行 , 势必会引起UI线程的ANR , 可以说工作线程就是来分担UI线程的压力 多开工作线程并不会提高UI的流畅度 , UI线程和工作线程两者是存在竞争关系的。同样是线程都需要等待CPU分配时间片 , 才能够真正运行起来的 。

    🔥 线程的分类 🔥 

    异步任务执行的方式 (五种)

    new Thread

    AsyncTask (轻量级的异步任务执行工具)

    HandlerThread (线程间可以通信且任务可直接运行)

    IntentService

    ThreadPoolExcutor (线程池)

    线程的优先级 (设置线程优先级的两种方式)

    线程完成创建后执行 start() 函数后并不是立刻执行得到调度的 , 线程的优先级越高获得CPU时间片的概率越大 , 那么该线程就能够越早得到调度 。

    android.os.Process.setThreadPriority

    java.lang.Thread.setPriority

    线程的状态 ( 四种 )

    sleep (暂时让出CPU的使用权) 

    yeild (多个线程同步的场景)

    join (线程之间顺序的场景)

    wait-notify(notifyAll)

     🔥 线程之间通讯 🔥

    子线程向主线程发送消息

    主线程向自线程发送消息

    🔥 线程安全 🔥 

    关键字同步

            synchronized

            volatile

    JUC工具

            Lock

                    WriteLock

                    ReadLock

                    ReentrantLock

            Atomic

                    AtomicInteger

                    AtomicBoolean

                    AtomicStampedReference

             Concurrent

                    CountDownLatch

                    CyclicBarrier

                    Semaphore

    并发容器

            CopyOnWriteArrayList

            ConcurrentHashMap

    🔥 线程与进程 🔥 

    一个进程至少包含一个线程

    进程可以包含多个线程

    进程在执行过程中拥有独立的内存空间 , 而线程运行在进程内

    🔥 线程的几种创建方式 🔥 

    new Thread

     可复写Thread 的run() 函数 。也可传递Runnable对象 , 更近灵活。

    缺点 : 缺乏统一管理 , 可能无限制新建线程 , 相互之间竞争 , 及可能只用过多系统资源导致死机或oom

    传递Runnable对象

    Java

    1. new Thread(new Runnable() {
    2. @Override
    3. public void run() {
    4. }
    5. }).start();

    Kotlin

    1. Thread {
    2. }.start()

     重写Thread的 run() 函数

    Java

    1. class MyThread extends Thread{
    2. @Override
    3. public void run() {
    4. super.run();
    5. }
    6. }
    7. new MyThread().start();

    Kotlin

    1. internal class MyThread : Thread() {
    2. override fun run() {
    3. super.run()
    4. }
    5. }
    6. MyThread().start()

     AsyncTask

    轻量级的异步任务工具类 , 提供任务执行的进度回调给UI线程

    场景 : 需要知道任务执行的进度 , 多个任务串行执行 。

    缺点 : 生命周期和宿主的生命周期不同步 , 有可能发生内存泄露 (解决方案就是在创建AsyncTask类前面加上static关键字), 默认情况所有任务串行执行 。

     Java

    1. MyAsyncTask asyncTask=new MyAsyncTask();
    2. MyAsyncTask asyncTask2=new MyAsyncTask();
    3. /// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
    4. asyncTask.execute("execute MyAsyncTask one");
    5. asyncTask2.execute("execute MyAsyncTask two");
    6. /// 传递AsyncTask.THREAD_POOL_EXECUTOR参数可以做到并发执行
    7. /// 很多文章说会并发执行,但是跟串行没有区别(有待考证)
    8. //asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask one");
    9. //asyncTask2.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask two");
    1. class MyAsyncTask extends AsyncTask{
    2. private static final String TAG="MyAsyncTask";
    3. @Override
    4. protected String doInBackground(String... params) {
    5. ///1、向onProgressUpdate()函数抛出执行UI的更显操作
    6. for (int i=0;i<10;i++){
    7. publishProgress(i*10);
    8. }
    9. return params[0];
    10. }
    11. @Override
    12. protected void onPostExecute(String result) {
    13. super.onPostExecute(result);
    14. ///3、执行结果
    15. System.out.println(TAG+"result: "+result);
    16. }
    17. @Override
    18. protected void onProgressUpdate(Integer... values) {
    19. super.onProgressUpdate(values);
    20. ///2、此处执行UI的更新操作
    21. System.out.println(TAG+"onProgressUpdate: "+values[0].intValue());
    22. }
    23. }
    1. I/System.out: MyAsyncTaskonProgressUpdate: 0
    2. I/System.out: MyAsyncTaskonProgressUpdate: 10
    3. I/System.out: MyAsyncTaskonProgressUpdate: 20
    4. I/System.out: MyAsyncTaskonProgressUpdate: 30
    5. I/System.out: MyAsyncTaskonProgressUpdate: 40
    6. I/System.out: MyAsyncTaskonProgressUpdate: 50
    7. I/System.out: MyAsyncTaskonProgressUpdate: 60
    8. I/System.out: MyAsyncTaskonProgressUpdate: 70
    9. I/System.out: MyAsyncTaskonProgressUpdate: 80
    10. I/System.out: MyAsyncTaskonProgressUpdate: 90
    11. I/System.out: MyAsyncTaskresult: execute MyAsyncTask one
    12. I/System.out: MyAsyncTaskonProgressUpdate: 0
    13. I/System.out: MyAsyncTaskonProgressUpdate: 10
    14. I/System.out: MyAsyncTaskonProgressUpdate: 20
    15. I/System.out: MyAsyncTaskonProgressUpdate: 30
    16. I/System.out: MyAsyncTaskonProgressUpdate: 40
    17. I/System.out: MyAsyncTaskonProgressUpdate: 50
    18. I/System.out: MyAsyncTaskonProgressUpdate: 60
    19. I/System.out: MyAsyncTaskonProgressUpdate: 70
    20. I/System.out: MyAsyncTaskonProgressUpdate: 80
    21. I/System.out: MyAsyncTaskonProgressUpdate: 90
    22. I/System.out: MyAsyncTaskresult: execute MyAsyncTask two

    Kotlin

    1. val asyncTask: MyAsyncTask = MyAsyncTask()
    2. val asyncTask2: MyAsyncTask = MyAsyncTask()
    3. /// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
    4. /// execute()是串行执行的,这样有一个弊端,单一个任务执行完成后才能执行下一个任务
    5. asyncTask.execute("execute MyAsyncTask one")
    6. asyncTask2.execute("execute MyAsyncTask two")
    7. /// 传递AsyncTask.THREAD_POOL_EXECUTOR参数可以做到并发执行
    8. /// 很多文章说会并发执行,但是跟串行没有区别(有待考证)
    9. //asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask one");
    10. //asyncTask2.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,"execute MyAsyncTask two");
    1. internal class MyAsyncTask : AsyncTask() {
    2. override fun doInBackground(vararg params: String?): String? {
    3. ///1、向onProgressUpdate()函数抛出执行UI的更显操作
    4. for (i in 0..9) {
    5. publishProgress(i * 10)
    6. }
    7. return params[0]
    8. }
    9. override fun onPostExecute(result: String) {
    10. super.onPostExecute(result)
    11. ///3、执行结果
    12. println(TAG + "result: " + result)
    13. }
    14. override fun onProgressUpdate(vararg values: Int?) {
    15. super.onProgressUpdate(*values)
    16. ///2、此处执行UI的更新操作
    17. println(TAG + "onProgressUpdate: " + values[0])
    18. }
    19. companion object {
    20. private const val TAG = "MyAsyncTask"
    21. }
    22. }

     AsyncTask

    串行和并行执行时 , 无需返回执行进度给UI的方式

    Java 串行执行

    以这种方式提交的任务,所有任务串行执行,即先来后到,但是如果其中有一条任务休眠了, 或者执行时间长 , 后面的任务都将被阻塞

    1. AsyncTask.execute(new Runnable() {
    2. @Override
    3. public void run() {
    4. for (int i=0;i<10;i++){
    5. System.out.println("任务一:"+i);
    6. }
    7. }
    8. });
    9. AsyncTask.execute(new Runnable() {
    10. @Override
    11. public void run() {
    12. for (int i=0;i<10;i++){
    13. System.out.println("任务二:"+i);
    14. }
    15. }
    16. });

    Kotlin 串行执行

    1. AsyncTask.execute {
    2. for (i in 0..9) {
    3. println("任务一:$i")
    4. }
    5. }
    6. AsyncTask.execute {
    7. for (i in 0..9) {
    8. println("任务二:$i")
    9. }
    10. }

     Java 并行执行

    使用 AsyncTask内置的THREAD_POOL_EXECUTOR 线程池并发执行

    1. AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
    2. @Override
    3. public void run() {
    4. for (int i=0;i<10;i++){
    5. System.out.println("任务一:"+i);
    6. }
    7. }
    8. });
    9. AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
    10. @Override
    11. public void run() {
    12. for (int i=0;i<10;i++){
    13. System.out.println("任务二:"+i);
    14. }
    15. }
    16. });
    1. I/System.out: 任务二:0
    2. I/System.out: 任务二:1
    3. I/System.out: 任务二:2
    4. I/System.out: 任务二:3
    5. I/System.out: 任务二:4
    6. I/System.out: 任务二:5
    7. I/System.out: 任务二:6
    8. I/System.out: 任务二:7
    9. I/System.out: 任务二:8
    10. I/System.out: 任务二:9
    11. I/System.out: 任务一:0
    12. I/System.out: 任务一:1
    13. I/System.out: 任务一:2
    14. I/System.out: 任务一:3
    15. I/System.out: 任务一:4
    16. I/System.out: 任务一:5
    17. I/System.out: 任务一:6
    18. I/System.out: 任务一:7
    19. I/System.out: 任务一:8
    20. I/System.out: 任务一:9

    Kotlin 并行执行

    使用 AsyncTask内置的THREAD_POOL_EXECUTOR 线程池并发执行

    1. AsyncTask.THREAD_POOL_EXECUTOR.execute {
    2. for (i in 0..9) {
    3. println("任务一:$i")
    4. }
    5. }
    6. AsyncTask.THREAD_POOL_EXECUTOR.execute {
    7. for (i in 0..9) {
    8. println("任务二:$i")
    9. }
    10. }

    HandlerThread 

    适用于主线程和工作线程通信 , 适用于持续性任务 , 比如轮询的场景 , 所有任务串行执行

    缺点 : 不会像普通线程一样主动销毁资源 , 会一直运行着 , 所以可能会造成内存泄露

    Java

    1. ///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
    2. ///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
    3. ///去轮询主线程里面的消息队列。
    4. ///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
    5. /// 需要调用quitSafely()函数停止任务
    6. HandlerThread thread=new HandlerThread("handler-thread");
    7. thread.start();
    8. ///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
    9. /// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
    10. /// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
    11. ThreadHandler handler=new ThreadHandler(thread.getLooper());
    12. handler.sendEmptyMessage(1000);
    13. ///thread.quitSafely();
    1. //定义成静态,防止内存泄漏
    2. static class ThreadHandler extends Handler{
    3. public ThreadHandler(Looper looper){
    4. super(looper);
    5. }
    6. @Override
    7. public void handleMessage(@NonNull Message msg) {
    8. super.handleMessage(msg);
    9. System.out.println("handleMessage: "+msg.what);
    10. System.out.println("handleMessage: "+Thread.currentThread().getName());
    11. }
    12. }
    1. I/System.out: handleMessage: 1000
    2. I/System.out: handleMessage: handler-thread

    Kotlin

    1. ///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
    2. ///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
    3. ///去轮询主线程里面的消息队列。
    4. ///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
    5. /// 需要调用quitSafely()函数停止任务
    6. ///HandlerThread并没有复写它的run()函数,也没有传递Runnable对象执行执行任务;
    7. ///是因为HandlerThread内部自行创建了Looper对象,并且能够像主线程里面的Looper一样
    8. ///去轮询主线程里面的消息队列。
    9. ///HandlerThread并不会因为一次任务的结束释放资源,可能会一直运行着。
    10. /// 需要调用quitSafely()函数停止任务
    11. val thread = HandlerThread("handler-thread")
    12. thread.start()
    13. ///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
    14. /// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
    15. /// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
    16. ///创建ThreadHandler对象时需要和HandlerThread的Looper绑定起来
    17. /// 我们在主线程或者其他子线程中使用ThreadHandler时就可以向HandlerThread发送消息了
    18. /// 消息的最终结果就会交给ThreadHandler的handleMessage函数来执行
    19. val handler = JavaHandlerThreadActivity.ThreadHandler(thread.looper)
    20. handler.sendEmptyMessage(1000)
    21. ///thread.quitSafely();
    1. //定义成静态,防止内存泄漏
    2. internal class ThreadHandler(looper: Looper?) : Handler(looper!!) {
    3. override fun handleMessage(msg: Message) {
    4. super.handleMessage(msg)
    5. println("handleMessage: " + msg.what)
    6. println("handleMessage: " + Thread.currentThread().name)
    7. }
    8. }
    1. I/System.out: handleMessage: 1000
    2. I/System.out: handleMessage: handler-thread

     IntentService

    IntentService拥有了Service的全部生命周期 , 包含了Service的全部特性 。与Service不同的是IntentService会创建一个线程来执行我们的耗时任务。

    适用于我们的任务需要跨页面读取任务执行的进度结果 。比如后台上传图片, 批量操作数据库等 。任务执行完成后就会自我结束 , 所以不需要手动stopservice , 这是它跟service的区分。

    Java

    1. class MyIntentService extends IntentService{
    2. /**
    3. * @param name
    4. * @deprecated
    5. */
    6. public MyIntentService(String name) {
    7. super(name);
    8. }
    9. @Override
    10. protected void onHandleIntent(@Nullable Intent intent) {
    11. int command=intent.getIntExtra("command",0);
    12. }
    13. }
    startService(new Intent());

    Kotlin

    1. internal class MyIntentService
    2. /**
    3. * @param name
    4. */
    5. @Deprecated("") constructor(name: String?) : IntentService(name) {
    6. override fun onHandleIntent(intent: Intent?) {
    7. val command = intent!!.getIntExtra("command", 0)
    8. }
    9. }
    startService(Intent())

     ThreadPoolExecutor

    使用处理大量耗时较短的任务场景 。

    1. Executors.newCachedThreadPool();//线程可复用线程池
    2. Executors.newFixedThreadPool(0)//固定线程数量的线程池
    3. Executors.newScheduledThreadPool(0)//可指定定时任务的线程池
    4. Executors.newSingleThreadExecutor();// 线程数量为1的线程池

    🔥 线程的优先级 🔥 

    线程的优先级具有继承性 , 在某线程中创建的线程会继承此线程的优先级 。那么我们在UI线程中创建了线程 , 则线程的优先级和UI线程的优先级一样 , 平等和UI线程抢占CPU时间片资源。

    JDK  Api , 限制了新设置的线程的优先级必须为[1~10] , 优先级priority的值越高 , 获取CPU时间片的概率越高。UI线程优先级为5

    java.lang.Thread.setPriority(int newPriority)

    Android Api ,  可以为线程设置更加精细的优先级 (-20~19) ,  优先级priority的值越低 , 获取 CPU时间片的概率越高 。UI线程优先级为-10 , 线程的优先级具有竞争性 , 所以会和我们的子线程进行竞争 。

    android.os.Process.setThreadPriority(int newPriority)

    setPriority 和  setThreadPriority 设置线程优先级的作用域是相互隔离的 。线程优化的时候需要我们间接性的设置线程的优先级 

    AsyncTask设置了优先级

    1. public class JavaTestPriorityActivity extends AppCompatActivity {
    2. private final static String TAG="JavaTestPriorityActivity";
    3. @Override
    4. protected void onCreate(Bundle savedInstanceState) {
    5. super.onCreate(savedInstanceState);
    6. setContentView(R.layout.activity_java_test_priority3);
    7. Thread thread=new Thread();
    8. thread.start();
    9. int ui_proi= Process.getThreadPriority(0);
    10. int th_proi=thread.getPriority();
    11. System.out.println(TAG+" Process.getThreadPriority(0) :"+ui_proi);
    12. System.out.println(TAG+" thread.getPriority() :"+th_proi);
    13. }
    14. }
    1. I/System.out: JavaTestPriorityActivity Process.getThreadPriority(0) :-10
    2. I/System.out: JavaTestPriorityActivity thread.getPriority() :5

    案例 

  • 相关阅读:
    前端页面加载性能优化
    【TB作品】MSP430,G2533单片机,红外发射,红外接收,红外通信,IR发射
    什么是强缓存、协商缓存?
    Mybatis多表查询
    Flask 源码分析总结:Context 上下文原理
    Linux基础 常见问题-模拟输入事件工具xdotool
    -1- threejs 场景常见的方法和属性
    微服务架构10个最重要的设计模式
    定制Centos7.9镜像
    ​在控制终端输入AT命令​
  • 原文地址:https://blog.csdn.net/u013491829/article/details/127538569