Android中Handler 、Thread和Runnable

作者: YoungTa0 | 来源:发表于2018-03-20 17:50 被阅读60次

    在多线程编程的时候,我们经常会用到Handler,Thread和Runnable这三个类,我们来看看这三个类之间是怎么样的关系?
    首先说明Android的CPU分配的最小单元是线程,Handler一般是在某个线程里创建的,因而Handler和Thread就是相互绑定的,一一对应。 而Runnable是一个接口,不会自己开启一个线程,依旧运行在UI线程,Thread是Runnable的子类,实现Runnable接口来开启线程是把Runnable对象至于Thread中运行。

    1.Handler

    1.1Handler定义

    主要接受子线程发送的数据, 并用此数据配合主线程更新UI ,或者利用post,postdelay方法来实现延时操作

    解释:Handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例都会绑定到创建他的线程中(一般是主线程)

    1.2.Handler方法

    Handler中分发消息的一些方法
    post(Runnable)
    postAtTime(Runnable,long)
    postDelayed(Runnable long)
    sendEmptyMessage(int)
    sendMessage(Message)
    sendMessageAtTime(Message,long)
    sendMessageDelayed(Message,long)
    removecallbacks(Runnable)
    方法postdelay的作用是将Runnable里面的run方法延迟后运行
    方法removecallbacks方法是删除指定的Runnable对象 
    

    2.Runnable和Thread

    我们常说开启线程的方法有两个,一:实现Runnable接口;二:继承Thread类。但无论怎么样,开启线程都是通过Thread开启,Runnable并不能开启线程,实现Runnable接口只是作为Thread对象的参数来开启线程。
    Runnable就相当于一个作业,而Thread才是真正的处理线程。

    2.1Runnable和Thread的区别

    首先阐述实现Runnable的好处:
    ●java不允许多继承,因此实现了Runnable接口的类可以再继承其他类。
    ●方便资源共享,即可以共享一个对象实例???(从很多博客中看到这样描述,但是此处有疑问,例子如下)(PS:继承Thread开启线程也可以资源共享,但是容易出现异常)

    使用Thread不能资源共享实例:

    public class MyThreadWithExtends extends Thread {  
      
        private int tickets = 10;  
      
        @Override  
        public void run() {  
      
            for (int i = 0; i <= 100; i++) {  
                if(tickets>0){  
                    System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);  
                }  
            }  
        }  
          
          
        public static void main(String[] args) {  
            MyThreadWithExtends thread1 = new MyThreadWithExtends();  
            MyThreadWithExtends thread2 = new MyThreadWithExtends();  
            MyThreadWithExtends thread3 = new MyThreadWithExtends();  
      
            thread1.start();  
            thread2.start();  
            thread3.start();  
              
            //每个线程都独立,不共享资源,每个线程都卖出了10张票,总共卖出了30张。如果真卖票,就有问题了。  
        }  
      
    }
    

    运行结果:
    Thread-0--卖出票:10
    Thread-2--卖出票:10
    Thread-1--卖出票:10
    Thread-2--卖出票:9
    Thread-0--卖出票:9
    Thread-2--卖出票:8
    Thread-1--卖出票:9
    Thread-2--卖出票:7
    Thread-0--卖出票:8
    Thread-2--卖出票:6
    Thread-2--卖出票:5
    Thread-2--卖出票:4
    Thread-1--卖出票:8
    Thread-2--卖出票:3
    Thread-0--卖出票:7
    Thread-2--卖出票:2
    Thread-2--卖出票:1
    Thread-1--卖出票:7
    Thread-0--卖出票:6
    Thread-1--卖出票:6
    Thread-0--卖出票:5
    Thread-0--卖出票:4
    Thread-1--卖出票:5
    Thread-0--卖出票:3
    Thread-1--卖出票:4
    Thread-1--卖出票:3
    Thread-1--卖出票:2
    Thread-0--卖出票:2
    Thread-1--卖出票:1
    Thread-0--卖出票:1

    使用Thread能资源共享实例:

    public class TicketThread extends Thread{
    
        private int ticket = 10;
    
        public void run(){
            for(int i =0;i<10;i++){
                synchronized (this){//解决每个线程共享了对象myRunnable的资源,卖出的总票数是对的,但是顺序是乱的问题
                    if(this.ticket>0){
                        try {
                            Thread.sleep(100);
                            System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        public static void main(String[] arg){
            TicketThread t1 = new TicketThread();
            new Thread(t1,"线程1").start();
            new Thread(t1,"线程2").start();
            //也达到了资源共享的目的,此处网上有各种写法,很多写法都是自圆其说,举一些特殊例子来印证自己的观点,然而事实却不尽如此。
        }
    }
    

    运行结果
    线程1卖票—->10
    线程1卖票—->9
    线程1卖票—->8
    线程2卖票—->7
    线程2卖票—->6
    线程1卖票—->5
    线程1卖票—->4
    线程2卖票—->3
    线程2卖票—->2
    线程1卖票—->1

    实现Runnable接口开启线程两种方式都能实现资源共享

    2.2总结:在程序开发中只要是多线程肯定永远以实现Runnable接口为主。

    实现Runnable接口相比继承Thread类有如下好处:

    1、避免继承的局限,一个类可以继承多个接口。

    2、适合于资源的共享。

    3线程池

    既然实现了多线程那必然离不开管理这些线程,当问题比简单时一个或者几个线程就OK了,也涉及不到效率问题。一旦线程数
    量多起来的时候,必然躲不过这些线程的创建与销毁,而往往这是很浪费时间的。这时就需要利用线程池来进行管理,既免去了>我们创建线程和销毁线程的代码,也提高了程序的效率。

    3.1为什么使用线程池

    1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率

    例如:
    记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3
    如果T1+T3>T2,那么是不是说开启一个线程来执行这个任务太不划算了!
    正好,线程池缓存线程,可用已有的闲置线程来执行新任务,避免了T1+T3带来的系统开销

    2.线程并发数量过多,抢占系统资源从而导致阻塞

    我们知道线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况
    运用线程池能有效的控制线程最大并发数,避免以上的问题

    3.对线程进行一些简单的管理

    比如:延时执行、定时循环执行的策略等
    运用线程池都能进行很好的实现

    相关文章

      网友评论

        本文标题:Android中Handler 、Thread和Runnable

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