zoukankan      html  css  js  c++  java
  • android Thread和Runable区别,精讲(有疑问)

    网上总是说Runable和Thread可以实现线程,这导致我对Thread和Runable有错误的理解,谁让当时不求甚解,让我一直以为实现Runable可以开启线程。

    看过源码后进行区分这两者。

    无论怎么样,线程都是通过Thread创建的。

    其一:Runable只是一个接口,不会开启一个线程,依旧是运行在UI线程中。                     

    public interface Runnable {
    
        /**
         * Starts executing the active part of the class' code. This method is
         * called when a thread is started that has been created with a class which
         * implements {@code Runnable}.
         */
        public void run();
    }

      可以看到,Runable在源码中只有run方法,并且Runable可以在主线程执行修改UI的代码,并且“OK”的执行一定是在输出10个“runable”后,所以,Runable并没有开启线程,依旧是运行在UI线程中

    protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            runnable.run();
            Log.d("hello", "OK");
    
    
        }
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    for(int i = 0;i<10;i++) {
                        textView.setText("runable");
                        Log.d("hello", "runable");
                    }
                }
    };

    其二:Thread如何开启的线程,和Runable什么关系?

    源码部分:

    public class Thread implements Runnable {

    最直接的一部分,实现Runable的接口。下面看看Thread的构造函数。

    public Thread() {
        create(null, null, null, 0);
    }

     这是其中之一的构造函数,调用了create()方法,其他构造函数依然调用该方法。下面看看create()方法。

    private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
            Thread currentThread = Thread.currentThread();
            if (group == null) {
                group = currentThread.getThreadGroup();
            }
    
            if (group.isDestroyed()) {
                throw new IllegalThreadStateException("Group already destroyed");
            }
    
            this.group = group;
    
            synchronized (Thread.class) {
                id = ++Thread.count;
            }
    
            if (threadName == null) {
                this.name = "Thread-" + id;
            } else {
                this.name = threadName;
            }
        
            this.target = runnable;
    
         this.stackSize = stackSize; this.priority = currentThread.getPriority(); this.contextClassLoader = currentThread.contextClassLoader; // Transfer over InheritableThreadLocals. if (currentThread.inheritableValues != null) { inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues); } // add ourselves to our ThreadGroup of choice this.group.addThread(this); }

     虽然比较多,但是只需要看这一行代码,this.taeget = runable;而在Thread类的run()方法和start()方法中,

      public void run() {
            if (target != null) {
                target.run();
            }
        }

      

    /**
         * Starts the new Thread of execution. The <code>run()</code> method of
         * the receiver will be called by the receiver Thread itself (and not the
         * Thread calling <code>start()</code>).
         *
         * @throws IllegalThreadStateException - if this thread has already started.
         * @see Thread#run
         */
        public synchronized void start() {
            checkNotStarted();
    
            hasBeenStarted = true;
    
            nativeCreate(this, stackSize, daemon);
        }

    这两个形成了两个方法的区别:

    •   start: 

               用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

    •   run:
        run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.。

    这样也就很清晰可见,那么如何开启线程,

        其中之一,和上文类比。

     Thread t = new Thread(runnable);
            t.start();
            Log.d("hello","ok");
        }
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
               textview.settext(“runable”);
    for(int i = 0;i<10;i++) { Log.d("hello", "runable"); } } };
    1. 执行Thread的构造方法,然后执行oncreate方法。this.target = runable; 
    2. 执行t.start();等得到cpu时间片,执行run()方法。
    3. 执行run()方法,target.run();  (也就是在子线程执行runable.run()。)

    根据执行结果也看到真正的开启了线程,“OK”的输出并不按代码执行顺序。

    06-13 19:32:26.252 21369-21369/? D/hello: ok
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable
    06-13 19:32:26.252 21369-21429/? D/hello: runable

     但是可以修改Ui(textview.settext)?!!!!!!执行的是runable.run()。(不应该在子线程执行这句话吗?子线程不是不能修改UI吗?)

       

    为其添加按钮监听,打印线程 t 的名字,为Thread-76777  

      button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    t.start();
                }
            });

     得到我想要的结果:: FATAL EXCEPTION: Thread-76777 ,android.view.ViewRootImpl$CalledFromWrongThreadException:

        那么,问题在于。为什么上述情况可以修改,而添加按钮点击后执行t.start()无法修改UI

      希望有人看到帮我解答一下这个疑问,如果本文有错误也希望指出。转载请注明出处http://www.cnblogs.com/yuhanghzsd/p/5581918.html 

    原因:

    onCreate中极短的时间内, viewRootImpl还没有创建完成, new Thread()是可以“修改”ui的.

    因为那个时候viewRootImpl还没有创建.

    当使用按钮之后, 就不行了. 因为这个时候的view树肯定是已经创建完毕了. 
    只有创建该View的线程才能修改和更新改view.
    因为ViewRootImpl是在ActivityThread类中的主线程创建的. 所以只有主线程能更新ui.

     END!

  • 相关阅读:
    java 单例模式-饿懒汉模式
    Java注解
    Java集合
    Java数据类型
    java实现多线程三种方法
    Java并发 线程池
    spring ioc(反转控制)
    事件驱动的Java框架
    js 标签属性与导航
    input 标签和a标签实现超链接的区别
  • 原文地址:https://www.cnblogs.com/yuhanghzsd/p/5581918.html
Copyright © 2011-2022 走看看