buder

2017-11-29 由runnable说起Android中的子线程和主线程

1.首先纠正一个观点,就是runnable运行在子线程中是错误的观念。runnable只是创建了一个执行任务的对象,但是它本身并不会创建一个新的子线程,Runable只是给你接口让你实现工作线程的工作事务,然后附加到你new thread的线程上或post的线程中,其本身并不会创建线程

几个常识性的概念需要清楚的:

(1)Runnable中的run方法:run()方法在每个线程启动时都会首先执行,启动几个线程就有几个线程去执行这个run()方法。 run()方法是Runnabl接口的抽象方法。实现Runnabl接口就必须实现它的方法,而这个方法就是线程的入口。

(2)实现了Runnable的类只是定义了一个任务,一般还要把实现了Runnable的类的对象传递给一个Thread对象才能开启线程。开启线程的两种方式:

一:

Runnable r=new Runnable(){
    public void run() {
        while(true){
            System.out.println("1111");
        }                
    }
}
Thread t = new Thread(r);
t.start();

或者下面的形式也可以开启一个线程,也就是重写Thread类的run方法:

二:

class First extends Thread{
    public void run(){
        while(true){
            System.out.println("11111111");
        }
    }
}
public class Test{
    public static void main(String []args){
        Thread t=new First();
        t.start();       
    }
}

(3)跟进源码一探究竟:

你可以再看一下Thread类的源代码:

private Runnable target;
 
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}
 
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
    //其它代码   
    this.target = target;
    //其它代码
}
 
public void run() {
    if (target != null) {
        target.run();
    }
}

所以使用第一种方式开启线程的时候,target就是构造方法传过来的Runnable对象,就会去执行target的run方法,也就是Runnable对象的任务,如果是第二种方式,则执行已经重写过的run方法里的任务。

再看一下Thread类的start方法:

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);
    start0();
    if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
}
 
private native void start0();

 

start0方法用的native关键字,百度了一下,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。

可以再看一下JDK的文档,关于Thread类的start方法的介绍:
public void start()
         使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 

所以我觉得start方法里应该就是做了让虚拟机调用该线程的 run 方法,也就是Thread类的run方法,也就执行了run方法里的任务

Thread的run方法是调用Runnable的run方法的。Thread类是implements了Runnable接口;调用的start()方法,其实就是Thread类中的start()方法;代理设计模式。

 

2.handler.post在主线程中执行,具体代码:

自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了。Handler的post()方法就是将Runnable中的代码段传送到主线程。

public class MainActivity extends Activity {
    TextView valueTv;
    public Handler mHandler;
    private MyThread thread;
    // 定义一个自己的线程
    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("线程开始运行");
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    valueTv.setTextColor(Color.RED);
                    valueTv.setTextSize(30);
                    valueTv.setText("从线程中传过来的代码段");
                    System.out.println("执行runnable代码的线程:"+Thread.currentThread().getName());
                }
            };
            //上面代码中的runnable线程体经过post后会直接传送到主线程中执行修改字体的操作。
            //post直接可以把一段代码当做变量一样传递,但是请不要传送耗时操作的代码到主线程中
            mHandler.post(r);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        valueTv = (TextView)findViewById(R.id.vale_textView);
        mHandler = new Handler();
        thread = new MyThread();
        // 启动线程
        thread.start();
    }
}

方法的官方解释是:

The runnable will be run on the thread to which this handler is attached.

既是说,这个开启的runnable会在这个handler所依附线程中运行,而这个handler是在UI线程中创建的,所以 
自然地依附在主线程中了。

postDelayed(new Runnable()) 而没有重新生成新的 New Thread()

3.View.post(Runnalbe)方法,在post(Runanble action)方法中,View获得当前主线程(即UI线程)的handler,然后将action对象post到handler里面去,在Handler里,它将传递过来的action对象封装成一个Message(Message 的callback为action),然后将其投入到UI线程的消息循环中,在handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法,而此时,已经路由到UI线程里,因此我们可以毫无顾虑来更新UI。

4.主要参考如下博客:

http://blog.sina.com.cn/s/blog_77c6324101016jp8.html

https://www.cnblogs.com/huaqing-wkc/p/4940190.html

 

常见的新建线程的方法是:

    Thread thread = new Thread();

    thread.start();

 

    HandlerThread thread = new HandlerThread("string");

    thread.start();

posted on 2017-11-29 23:22  buder  阅读(414)  评论(0编辑  收藏  举报

导航