Android开发Android开发经验谈Android开发

Android中Handler 、Thread和Runnable

2018-03-20  本文已影响60人  YoungTa0

在多线程编程的时候,我们经常会用到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.对线程进行一些简单的管理

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

上一篇下一篇

猜你喜欢

热点阅读