美文网首页
线程间通信原理及Android多线程

线程间通信原理及Android多线程

作者: angeliur | 来源:发表于2019-09-16 07:19 被阅读0次
    线程间交互
    • 一个线程启动别的线程:new Thread().start()、Executor.execute() 等

    • 一个线程终结另一个线程

      • Thread.stop() 可以立即停止线程,现在已废弃,不推荐使用

        Thread thread = new Thread(){
          @Override
          public void run() {
            for (int i = 0; i < 100000; i++) {
                System.out.println(i);
            }
          }
        };
        
        thread.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //不管线程中的打印是否完成,调用stop()后立即停止
        thread.stop();
        

      • Thread.interrupt() 温和式终结:不立即、不强制

        • interrupted() 和 isInterrupted():检查(和重置)中断状态

          Thread.interrupted()在检查过后会重置中断状态,isInterrupted()不会重置

        • InterruptedException:如果在线程「等待」时中断,或者在中断状态「等待」,直接结束等待过程(因为等待过程什什么也不会做,而 interrupt() 的目的是让线程做完收尾工作后尽快终结,所以要跳过等待过程)。InterruptedException也会重置中断状态,所以在sleep结束等待,进入到InterruptedException也要保证interrupt可以执行

        Thread thread = new Thread(){
                    @Override
                    public void run() {
                        for (int i = 0; i < 100000; i++) {
                            if (Thread.interrupted()){
                                return;
                            }
                            try {
                                //如果线程在sleep等待,直接结束等待跳到catch中的InterruptedException
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                //InterruptedException也会重置中断状态,所以这里也需要return 保证中断可以执行
                                return;
                            }
                            System.out.println(i);
                        }
                    }
                };
        
                thread.start();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                thread.interrupt();
        
    • Object.wait() 和 Object.notify() / notifyAll()

      • 在未达到目标时 wait()
      • 用 while 循环检查
      • 设置完成后 notifyAll()
      • wait() 和 notify() / notifyAll() 都需要放在同步代码块里
      Thread thread = new Thread(){
        @Override
        public void run() {
          try {
            //如果线程在sleep等待,直接结束等待跳到catch中的InterruptedException
            Thread.sleep(300);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          printString();
        }
      };
      
      thread.start();
      
      Thread thread2 = new Thread(){
        @Override
        public void run() {
          try {
            //如果线程在sleep等待,直接结束等待跳到catch中的InterruptedException
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          initString();
        }
      };
      
      thread2.start();
      
      private synchronized void initString(){
        word = "hello";
        notifyAll();
      }
      
      private synchronized void printString(){
        while (word == null){
          try {
            //当word为空的时候,先释放锁让initString()获得锁进行赋值,然后再notifyAll()唤醒printString()
            wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        System.out.println(word);
      }
      
    • Thread.join():让另一个线程插在自己前面

      通过Thread.join()可以让几个线程按顺序来执行,或者通过Executors.newSingleThreadExecutor() 也可以实现线程顺序执行。

      Thread thread = new Thread(){
        @Override
        public void run() {
          try {
            Thread.sleep(300);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      };
      
      thread.start();
      
      Thread thread2 = new Thread(){
        @Override
        public void run() {
            try {
                //让thread先执行
            thread.join();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      };
      thread2.start();
      
    • Thread.yield():暂时让出自己的时间片给同优先级的线程

    Android的Handler机制
    • 本质:在某个指定的运行中的线程上执行代码
    • 思路:在接受任务的线程上执行循环判断
    • 基本实现:

    ​ Thread 里 while 循环检查
    ​ 加上 Looper(优势在于自定义 Thread 的代码可以少写很多):
    ​ 再加上 Handler(优势在于功能分拆,而且可以有多个 Handler)

    • Java 的 Handler 机制:

    ​ HandlerThread:具体的线程
    ​ Looper:负责循环、条件判断和任务执行
    ​ Handler:负责任务的定制和线程间传递

    推荐Handler详解文章:

    http://yifeiyuan.me/blog/f77487d3.html

    https://www.zhihu.com/question/34652589

    AsyncTask

    AsyncTask 的内存泄露

    众所周知的原因:AsyncTask 持有外部 Activity 的引用
    没提到的原因:执行中的线程不会被系统回收

    Java 回收策略:没有被 GC Root 直接或间接持有引用的对象,会被回收

    GC Root:

    1. 运行中的线程
    2. 静态对象
    3. 来自 native code 中的引用

    所以:AsyncTask 的内存泄露,其他类型的线程方案(Thread、Executor、HandlerThread)一样都有,所以不要忽略它们,或者认为 AsyncTask 比别的方案更危险。并没有。就算是使用 AsyncTask,只要任务的时间不长(例如 10 秒之内),那就完全没必要做防止内存泄露的处理。

    Service 和 IntentService
    • Service:后台任务的活动空间。适用场景:音乐播放器等。
    • IntentService:执行单个任务后自动关闭的 Service
    Executor、AsyncTask、HandlerThead、IntentService 的选择

    原则:哪个简单用哪个

    • 能用 Executor 就用 Executor
    • 需要用到「后台线程推送任务到 UI 线程」时,再考虑 AsyncTask 或者 Handler
    • HandlerThread 的使用场景:原本它设计的使用场景是「在已经运行的指定线程上执行代码」,但现实开发中,除了主线程之外,几乎没有这种需求,因为 HandlerThread 和 Executor相⽐比在实际应用中并没什什么优势,反而用起来会麻烦一点。不过,这二者喜欢用谁就用谁吧。
    • IntentService:首先,它是一个 Service;另外,它在处理理线程本身,没有比 Executor 有任何优势
    关于 Executor 和 HandlerThread 的关闭

    如果在界面组件里创建 Executor 或者 HandlerThread,记得要在关闭的时候(例如Activity.onDestroy() )关闭 Executor 和 HandlerThread。

    @Override
    protected void onDestroy() {
        super.onDestroy();
        executor.shutdown();
        handlerThread.quit(); // 这个其实就是停止 Looper的循环
    }
    

    相关文章

      网友评论

          本文标题:线程间通信原理及Android多线程

          本文链接:https://www.haomeiwen.com/subject/fikjyctx.html