Android 多线程

作者: suniney | 来源:发表于2018-06-05 14:20 被阅读29次

    多线程的应用在Android开发中常用方法主要有:

    1、继承Thread类
    2、实现Runnable接口
    3、AsyncTask
    4、Handler
    5、HandlerThread
    6、IntentService

    1、继承Thread类

    //方法1
    //创建线程类
    private class MyThread extends Thread {
            @Override
            public void run() {
                super.run();
            }
        }
    //实例化线程类,并开启
    MyThread myThread = new MyThread();
    myThread.start();
    
    //方法2
    //匿名类
     new Thread("线程名字") {
                @Override
                public void run() {
                    super.run();
                }
         };
    

    2、实现Runnable接口

    //方法1
    //创建线程类
    private class MyThread implements Runnable {
    
            @Override
            public void run() {
    
            }
        }
    MyThread myThread = new MyThread();
    Thread thread = new Thread(myThread);
    thread.start();
    
    //方法2
    //匿名类
     Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    
                }
            };
    Thread thread =new Thread(runnable);
    thread.start();
    

    与 “继承Thread类”对比

    与 “继承Thread类”对比

    3、AsyncTask

    public abstract class AsyncTask<Params, Progress, Result> { 
     ... 
    }
    // a. Params:开始异步任务执行时传入的参数类型,对应excute()中传递的参数
    // b. Progress:异步任务执行过程中,返回下载进度值的类型
    // c. Result:异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型保持一致
    
    
    private class MyTask extends AsyncTask<String, Integer, String> {
            //执行 线程任务前的操作
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
            //接收输入参数、执行任务中的耗时操作、返回 线程任务执行的结果
            @Override
            protected String doInBackground(String... strings) {
                return null;
            }
            //任务执行的进度
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
            }
            //接收线程任务执行结果、将执行结果显示到UI组件
            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
            }
            //取消任务
            @Override
            protected void onCancelled() {
                super.onCancelled();
            }
        }
    MyTask myTask = new MyTask();
    myTask.execute();
    myTask.cancel(true);
    
    

    AsyncTask的实现原理 = 线程池 + Handler
    线程池用于线程调度、复用 & 执行任务;Handler 用于异步通信
    其内部封装了2个线程池 + 1个Handler

    4、Handler

    image.png
    Handler使用共分为2种:使用Handler.sendMessage()、使用Handler.post()
    方式1:使用 Handler.sendMessage()
    /** 
      * 方式1:新建Handler子类(内部类)
      */
    
     // 步骤1:自定义Handler子类(继承Handler类) & 复写handleMessage()方法
    class mHandler extends Handler {
    
            // 通过复写handlerMessage() 从而确定更新UI的操作
            @Override
            public void handleMessage(Message msg) {
             ...// 需执行的UI操作
                
            }
        }
    
        // 步骤2:在主线程中创建Handler实例
            private Handler mhandler = new mHandler();
    
        // 步骤3:创建所需的消息对象
            Message msg = Message.obtain(); // 实例化消息对象
            msg.what = 1; // 消息标识
            msg.obj = "AA"; // 消息内容存放
    
        // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
        // 可通过sendMessage() / post()
        // 多线程可采用AsyncTask、继承Thread类、实现Runnable
            mHandler.sendMessage(msg);
    
        // 步骤5:开启工作线程(同时启动了Handler)
        // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    
    
    /** 
    * 方式2:匿名内部类
    */
    // 步骤1:在主线程中 通过匿名内部类 创建Handler类对象
    private Handler mhandler = new  Handler(){
                    // 通过复写handlerMessage()从而确定更新UI的操作
                    @Override
                    public void handleMessage(Message msg) {
                            ...// 需执行的UI操作
                        }
                };
    
      // 步骤2:创建消息对象
    Message msg = Message.obtain(); // 实例化消息对象
    msg.what = 1; // 消息标识
    msg.obj = "AA"; // 消息内容存放
      
    // 步骤3:在工作线程中 通过Handler发送消息到消息队列中
    // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    mHandler.sendMessage(msg);
    
    

    方式2:使用Handler.post()

    // 步骤1:在主线程中创建Handler实例
    private Handler mhandler = new mHandler();
    
    // 步骤2:在工作线程中 发送消息到消息队列中 & 指定操作UI内容
    // 需传入1个Runnable对象
    mHandler.post(new Runnable() {
                @Override
                public void run() {
                    ... // 需执行的UI操作 
                }
    
    });
    // 步骤3:开启工作线程(同时启动了Handler)
    // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    
    
    工作流程
    线程(Thread)、循环器(Looper)、处理者(Handler)之间的对应关系如下:
    image.png

    1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
    1个循环器(Looper) 可绑定多个处理者(Handler)
    1个处理者(Handler) 只能绑定1个1个循环器(Looper)

    5、HandlerThread

    内部原理 = Thread类 + Handler类机制,即:
    通过继承Thread类,快速地创建1个带有Looper对象的新工作线程
    通过封装Handler类,快速创建Handler & 与其他线程进行通信

    // 步骤1:创建HandlerThread实例对象
    // 传入参数 = 线程名字,作用 = 标记该线程
       HandlerThread mHandlerThread = new HandlerThread("handlerThread");
    
    // 步骤2:启动线程
       mHandlerThread.start();
    
    // 步骤3:创建工作线程Handler & 复写handleMessage()
    // 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
    // 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
      Handler workHandler = new Handler( handlerThread.getLooper() ) {
                @Override
                public boolean handleMessage(Message msg) {
                    ...//消息处理
                    return true;
                }
            });
    
    // 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
    // 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
      // a. 定义要发送的消息
      Message msg = Message.obtain();
      msg.what = 2; //消息的标识
      msg.obj = "B"; // 消息的存放
      // b. 通过Handler发送消息到其绑定的消息队列
      workHandler.sendMessage(msg);
    
    // 步骤5:结束线程,即停止线程的消息循环
      mHandlerThread.quit();
    
    

    6、IntentService

    步骤1:定义 IntentService的子类

    public class MyIntentService extends IntentService {
        
        public MyIntentService() {
            super("myIntentService");
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            String taskName = intent.getExtras().getString("taskName");
            switch (taskName) {
                case "task1":
                    Log.i("myIntentService", "do task1");
                    break;
                case "task2":
                    Log.i("myIntentService", "do task2");
                    break;
                default:
                    break;
            }
        }
    
        @Override
        public void onCreate() {
            Log.i("myIntentService", "onCreate");
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            Log.i("myIntentService", "onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.i("myIntentService", "onDestroy");
            super.onDestroy();
        }
    }
    

    步骤2:在Manifest.xml中注册服务

     <service android:name=".MyIntentService">
                <intent-filter>
                    <action android:name="cn.my.task"></action>
                </intent-filter>
            </service>
    

    步骤3:在Activity中开启Service服务

            //开启任务1
            Intent intent = new Intent(this,MyIntentService.class);
            intent.setAction("cn.my.task");
            Bundle bundle = new Bundle();
            bundle.putString("taskName","task1");
            startService(intent);
            //开启任务2
            Intent intent2 = new Intent(this,MyIntentService.class);
            intent2.setAction("cn.my.task");
            Bundle bundle2 = new Bundle();
            bundle2.putString("taskName","task2");
            startService(intent2);
    

    总结

    IntentService本质 = Handler + HandlerThread:
    通过HandlerThread 单独开启1个工作线程:IntentService
    创建1个内部 Handler :ServiceHandler
    绑定 ServiceHandler 与 IntentService
    通过 onStartCommand() 传递服务intent 到ServiceHandler 、依次插入Intent到工作队列中 & 逐个发送给 onHandleIntent()
    通过onHandleIntent() 依次处理所有Intent对象所对应的任务

    整理总结来源:Carson_Ho

    Handler 内存泄露

    解决方法1

    静态内部类+弱引用
    原理:静态内部类 不默认持有外部类的引用,从而使得 “未被处理 / 正处理的消息 -> Handler实例 -> 外部类” 的引用关系 的引用关系 不复存在。
    具体方案:将Handler的子类设置成 静态内部类
    同时,还可加上 使用WeakReference弱引用持有Activity实例
    原因:弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存

    解决方法2

    当外部类结束生命周期时,清空Handler内消息队列

    @Override
        protected void onDestroy() {
            super.onDestroy();
            mHandler.removeCallbacksAndMessages(null);
            // 外部类Activity生命周期结束时,同时清空消息队列 & 结束Handler生命周期
        }
    

    Java多线程sleep和wait的区别

    sleep是让线程休眠,到时间后会继续执行,wait是等待,需要唤醒再继续执行

    使用上
    从使用角度看,sleep是Thread线程类的方法,而wait是Object顶级类的方法。
    sleep可以在任何地方使用,而wait只能在同步方法或者同步块中使用。

    CPU及资源锁释放
    sleep,wait调用后都会暂停当前线程并让出cpu的执行时间,但不同的是sleep不会释放当前持有的对象的锁资源,到时间后会继续执行,
    而wait会放弃所有锁并需要notify/notifyAll后重新获取到对象锁资源后才能继续执行。
    即:sleep方法的线程不会释放对象锁,而wait() 方法会释放对象锁

    异常捕获
    sleep需要捕获或者抛出异常,而wait/notify/notifyAll不需要。

    相关文章

      网友评论

        本文标题:Android 多线程

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