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!

  • 相关阅读:
    Oracle常用命令大全(很有用,做笔记)
    表格驱动编程在代码中的应用
    mac 利用svn下载远程代码出现Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.
    FAILURE: Build failed with an exception.
    There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance
    react native TypeError network request failed
    Android向系统相册中插入图片,相册中会出现两张 一样的图片(只是图片大小不一致)
    react-native Unrecognized font family ‘Lonicons’;
    react-native SyntaxError xxxxx/xx.js:Unexpected token (23:24)
    Application MyTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.
  • 原文地址:https://www.cnblogs.com/yuhanghzsd/p/5581918.html
Copyright © 2011-2022 走看看