zoukankan      html  css  js  c++  java
  • Handler,Message,Runnable和多线程的理解

    每次在Android中遇到Handler,Runnable,Thread,HandlerThread,Message,Looper,MessageQueue及多线程的时候,我就一阵眩晕,感觉这些知识好难懂,今天就我的理解写一些总结,大部分内容都是从别人的博客中的理解。

    首先,看看Java中的多线程是如何实现的,在Java中实现多线程有两种方式,当然这两种方式放在Android也是能运行的:

      

    class MyThread extends Thread {
    public void run() {
    // 这里写上线程的内容
    }
    public static void main(String[] args) {
    // 使用这个方法启动一个线程
    new MyThread().start();
    }
    }
    class MyThread implements Runnable{
    public void run() {
    // 这里写上线程的内容
    }
    public static void main(String[] args) {
    // 使用这个方法启动一个线程
    new Thread(new MyThread()).start();
    }
    }

    前者是继承Thread类,后者是实现了Runnable接口,一般鼓励使用第二种方式,因为Java只允许单继承,但允许实现多个接口。

    接下来,看看线程的状态,线程状态一共5种,分别是:

          新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);

      就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);

      运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);

      阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)

      死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thread已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。

         现在开始Android的消息队列模式,Activity、Looper、Handler,Thread之间的的关系,那么一个线程怎样把消息放入主线程的消息队列呢?答案是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler的handleMessage接口来处理消息,见下图:

     

    image

    Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

    Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

    MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

    Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper

    Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

    由上图可以看到Handler负责将Message放入到MessageQueue中,一个MessafeQueue可以对应多个Handler,那么Handler和Runnable是什么关系呢。

    我们还是通过几个例子来具体看下:

    package com.xue.threaddemo;
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.Log;
    public class ThreadDemo extends Activity {
        private static final String TAG = "ThreadDemo";
        private int count = 0;
        private Handler mHandler =  new Handler();
        
        private Runnable mRunnable = new Runnable() {
            
            public void run() {
                //为了方便 查看,我们用Log打印出来
                Log.e(TAG, Thread.currentThread().getName() + " " +count);
                count++;
                setTitle("" +count);
                //每2秒执行一次
                mHandler.postDelayed(mRunnable, 2000);
            }
            
        };
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main); 
            //通过Handler启动线程
            mHandler.post(mRunnable);
        }
        
        @Override
        protected void onDestroy() {
            //将线程销毁掉
            mHandler.removeCallbacks(mRunnable);
            super.onDestroy();
        }
    }

    由上面代码可以看出handler通过mHandler.post(mRunnable)方法启动一个Runnable,然后执行Runnable方式中的的run()方法的代码。下面看看另外一个例子:

    package com.xue.handlerdemo;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.app.Activity;
    import android.view.Menu;
    
    public class MainActivity extends Activity {
        
        private int title = 0;
        private Handler handler =new Handler(){
            public void handleMessage(Message msg) {
                if(msg.what==1){
                    updateTitle();
                }
            };
        };
        
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new MyTask(), 1, 5000);
        }
        class MyTask extends TimerTask{
    
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Message message =new Message();
                message.what=1;
                handler.sendMessage(message);
            }
            
        }
        public void updateTitle(){
            setTitle("Welcome to Xue's APP " + title);
            title ++;
        }
    }

    上面代码中终于有Message出现了,在继承自TimerTask的类中,实例化一个Message对象,然后handler.sendMessage(message)把message传递给Handler,前面讲过Handler就是用来处理message的,上面代码中用sendmessage()发送消息,在Handler中用handleMessage(Message msg)接收消息,那么这个实例化的message在接收之前放在消息队列中,实例化的Message除了有what参数外常用的还有arg1,agr2,obj,前面两个是int类型,obj是object类型。下来看一个MARS老师的例子:

    package mars.barhandler;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ProgressBar;
    
    public class TestBarHandler extends Activity {
        /** Called when the activity is first created. */
        //声明控件变量
        ProgressBar bar = null;
        Button startButton = null;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            //根据控件的ID得到代表控件的对象,并为按钮设置监听器
            bar = (ProgressBar)findViewById(R.id.bar);
            startButton = (Button)findViewById(R.id.startButton);
            startButton.setOnClickListener(new ButtonListener());
        }
        //当点击startButton按钮时,就会执行ButtonListener的onClick方法
        class ButtonListener implements OnClickListener{
    
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                bar.setVisibility(View.VISIBLE);
                updateBarHandler.post(updateThread);
            }
            
        }
        //使用匿名内部类来复写Handler当中的handleMessage方法
        Handler updateBarHandler = new Handler(){
    
            @Override
            public void handleMessage(Message msg) {
                bar.setProgress(msg.arg1);
                Bundle bundle = msg.getData();
                updateBarHandler.post(updateThread);
                System.out.println("test---->" + bundle.getString("test"));
            }
            
        };
        //线程类,该类使用匿名内部类的方式进行声明
        Runnable updateThread = new Runnable(){
            int i = 0 ;
            @Override
            public void run() {
                System.out.println("Begin Thread" + i);
                i = i + 10 ;
                //得到一个消息对象,Message类是有Android操作系统提供
                Message msg = updateBarHandler.obtainMessage();
                
                //将msg对象的arg1参数的值设置为i,用arg1和arg2这两个成员变量传递消息,优点是系统性能消耗较少
                msg.arg1 = i ;
                Bundle bundle = new Bundle();
                bundle.putString("test", "test bundle");
                msg.setData(bundle);
                try {
                    //设置当前显示睡眠1秒
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //将msg对象加入到消息队列当中
                if( i > 100){
                    //如果当i的值为100时,就将线程对象从handler当中移除
                    updateBarHandler.removeCallbacks(updateThread);
                    System.out.println(">>>>>>");
                }else{
                    updateBarHandler.sendMessage(msg);
                    System.out.println("<<<<<<");
                }
            }
        };
    }

    这个例子非常经典,点击开始按钮后,updateBarHandler.post(updateThread)通过post方法handler启动了一个runnable,在继承自Runnable的类中终于又出现Message啦,这次不仅简单的让msg.arg1=i而且还加入了Bundle类型的数据msg.setData(bundle);然后当然是sendMessage了,相应的在Handler中就会有handlerMessage接收消息,这儿可以注意到第一个例子没有使用Message机制,所以第一个例子仅仅是使用post方法启动了个runnable,而在runnable没有使用sendMessage方法发送消息,故Handler没有加入handlMessage方法,仅仅实例化了个Handler()。回到本例子中,Handler接收到消息后,bar.setProgress(msg.arg1)更新了UI,而且接收了Runnable发送的参数,然后再用post方法循环到Runnable一直到i>100,updateBarHandler.removeCallbacks(updateThread)这行代码非常重要,作用是把线程对象从handler当中移除,那么不移除会有什么后果,不移除的话即时关闭这个应用,线程不会停,依然在执行。
        许多初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask由于目前市面上的书籍等资料都没有谈到这些问题,遇到的时候总是感觉一阵眩晕,我的理解还是较为浅薄,望海涵。

        由于不满意自己对Handler的理解,贴上一篇博文,这里面讲的非常详细:http://52android.blog.51cto.com/2554429/470542

    每一个程序猿都是文艺青年!!!
  • 相关阅读:
    【Mybatis plus 3.2】怎么操作?看看我!(update、limit、between)
    #1024程序员节# 节日快乐
    ERROR: ...hbase.PleaseHoldException: Master is initializing
    【Flume】安装与测试
    【Storm】与Hadoop的区别
    【Storm】核心组件nimbus、supervisor、worker、executor、task
    LeetCode124:Binary Tree Maximum Path Sum
    LeetCode123:Best Time to Buy and Sell Stock III
    LeetCode122:Best Time to Buy and Sell Stock II
    LeetCode121:Best Time to Buy and Sell Stock
  • 原文地址:https://www.cnblogs.com/xue2b/p/3091168.html
Copyright © 2011-2022 走看看