NO.2 Android 线程间交互

社会主义新天地 提交于 2020-03-01 10:05:14

NO.2 Android 线程间交互

零蚀


线程的终止

  • 一个线程终止另一个线程

    Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
    
            }
        });
    thread.start();
    thread.stop();
    

    线程里 有一个非常有效的终止线程的方法,可以使用stop来有效的结束一个线程,但是这个api在4.1的时候就已经被弃用了,因为结果是不可预期的,当结束线程时候,不能了解到线程所做的工作是什么,所以对这种不可控的因素,是不可靠的。

    Thread thread=new Thread(){
        @Override
        public void run() {
            //重置interrupt的状态
            if(Thread.interrupted()){
                // 收尾
                return;
            }
            // 下面的方法不会改变interrupt标记的状态
            //if(isInterrupted()){
            //    return;
            //}
        }
    };
    thread.start();
    thread.interrupt();
    

    interrupt方法并非像stop即死,它是给这个线程做个中断标记。通知线程将被中断。如果线程在合适的位置进行终止,如上述代码。

  • Thread.sleep

    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        // InterruptedException监测到状态为true则抛异常
        e.printStackTrace();
    }
    

    在睡眠时候加上这个异常,是为了防止线程睡眠状态过好,而当interrupt状态发生改变,那么睡眠就结束了,进入异常阶段,而InterruptedException也会将interrupt状态进行重置,所以如果需要关闭外部耗/循环时操作,需要return!这sleep即用来睡眠也用来被打断。。

    SystemClock.sleep(1000);
    

    这也是睡眠操作,但是他不会抛异常,也就是不接受打断,他只是睡,雷打不醒的那种。

  • wait & notify

    wait & notify 是运行在synchornized里面的,并对其产生作用。

    
    public synchronized void init_name(){
        
        name = "无所不知的神棍";
    }
    
    public synchronized void print_name(){
        while(name ==null){
    
        }
        System.out.println(name);
    }
    new Thread(){
        @Override
        public void run() {
            SystemClock.sleep(1000);
            init_name();
        }
    }.start();
    
    new Thread(){
        @Override
        public void run() {
            SystemClock.sleep(500);
            print_name();
        }
    }.start();
    

    上述方法会出现死锁情况,

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8WEKNgWs-1582965367146)(media/15829464285105/15829531645688.jpg)]

    处理方式:

     public synchronized void init_name(){
    
        name = "无所不知的神棍";
        notify();
        //   notifyAll();
    }
    
    public synchronized void print_name(){
        while(name ==null){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name);
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4abXHCbH-1582965367147)(media/15829464285105/15829545245858.jpg)]

    在此interrupt也会唤醒wait,由于wait不清楚是被谁唤醒的,所以wait之前必须要加while循环♻️。wait()& notify() 不是Thread的方法,是object方法,他的作用对象或说是依附对象是monitor,是通过monitor来规定线程们的wait行为,所以所处位置必须是object的方法。

  • Thread.join()

    join()的方法和python的方法一致,当thread1.join后先执行thread1线程的内容才会执行thread2后续的方法。

    final Thread thread1=new Thread(){
            @Override
            public void run() {
                super.run();
            }
        };
    thread1.start();
    Thread thread2=new Thread(){
        @Override
        public void run() {
            try {
                thread1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    thread2.start();
    
  • Thread.yield()

    yield 方法也和python一致,yield是将自己的时间片让出去,让其他线程执行完毕之后才会执行。

    Thread thread2=new Thread(){
       @Override
       public void run() {
           //....
           Thread.yield();
           // ...
       }
    };
    thread2.start();
    

Handler机制

  • handler用法

    handler作用于指定中的运行中线程的代码进行操作。

    // handler默认操作(post)的是new Handler的线程,当然我们也可以定义handler操作的对象
    // new Handler(Looper.getMainLooper());
    Handler handler=new Handler();
    handler.post(new Runnable() {
         @Override
         public void run() {
            // 将内容推向主线程
         }
    });
    

    handler中设置了task,loop则是对task.run进行操作管理,这里的post是将内容推入Queue中,由MessageQueue这个链表队列。

  • ThreadLocal

    ThreadLocal是针对线程本地的高速缓存的变量设置,这种设置互不影响,比如以下案例,每个线程的设置获取都不会影响到其他线程的使用。

    final ThreadLocal<Integer> age = new ThreadLocal<>();
    
    
    new Thread(){
        @Override
        public void run() {
            age.set(10);
            age.get();
        }
    }.start();
    
    new Thread(){
        @Override
        public void run() {
            age.set(20);
            age.get();
        }
    }.start();
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1XwyWsud-1582965367147)(media/15829464285105/15829613947284.jpg)]

  • Looper

    源码

    // HandlerThread 
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    
    1. 这里的Looper.prepare() 是创建了一个loop完成其初始化工作
    2. Looper.myLooper()指定了当前执行的线程
    3. Looper.loop()是反复while ture loop其中的task任务。

    loop()源码

    public static void loop() {
        ...
         for (;;) {
            ...
            // 分发消息,这里调用的是handler的dispatchMessage()
            msg.target.dispatchMessage(msg);
            // dispatchMessage源码中,如果一旦拿到了message则,callback信息的内容。
            ...
        ...
    }
    

内存泄漏

 new NewAsyncTask().execute(10,10,10);
class NewAsyncTask extends AsyncTask<Integer,Integer,String>{

        @Override
        protected String doInBackground(Integer... integers) {
            return null;
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }
    }

AsyncTask在activity里定义会持有Activity的引用,但不一定导致不能被回收,垃圾回收机制在判定一个模块是否可以被回收并非是看它有没有引用的指向,这是不可靠的,而是查看它是否含有gc root相关联的引用,如果是含有相关联的引用,则判定他是不可被垃圾回收器回收的内容。

  1. 第一种是运行中的线程就具有gc root,所以在asynctask在运行时调用的thread导致它含有gc root,容易导致内存泄漏,无法释放。
  2. 第二种是static,他是含有gc root的。
  3. JNI方法的local变量或参数;全局JNI引用;用于同步的监控对象

以上便是导致内存泄漏的根源。在页面关闭之后如果AsyncTask还运行了一段时间,其实没有什么影响,和软引用,弱引用已经没有太大的关系。如果很长时间,就不要放在activity中了。


🔗 前言
🔗 Android 线程列表
🔗 NO.1 Android 多线程与线程同步

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!