你不知道的Runnable接口,深度解析Runnable接口

你不知道的Runnable接口,深度解析Runnable接口本文描述的是 Android 中的 Runnable 接口 因 Android 中的线程源自于 Java 所以首先需要了解 Java 中的线程 有关 Java 中的线程请看这篇文章 Android 线程一 线程 Java 开发中 我们实现多线程 有两种方式 一种是继承 Thread 类 一种是实现 Runnable 接口 但是 我们真的理解 Runnable Runnable 和 Thread 一样吗 都是开

    本文描述的是Android中的Runnable接口 。因Android中的线程源自于Java,所以首先需要了解Java中的线程,有关Java中的线程请看这篇文章Android(线程一) 线程  !

    Java开发中,我们实现多线程,有两种方式, 一种是继承Thread类,一种是实现Runnable接口。但是,我们真的理解Runnable?Runnable和Thread一样吗?都是开启新的线程吗? 为何明明在子线程使用Handler的post(Runnable),最终还是在主线程中执行呢?…带着这些疑问,我们来开始今天的博文。本文的例子是基于Android Studio。

一、首先通过例子实现这两种方式。

1、继承Thread类。

      Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了。

首先新建一个MyThread类继承自Thread类,重写run()方法,在控制输入传递的文本,

 

public class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { System.out.println("MyThread is " + name); } }

接着创建该类,启动该线程(Thread类的start()方法),并输出线程的id,

 

 

public class Test1 { public static void main(String[] args){ MyThread myThread1=new MyThread("线程1"); MyThread myThread2=new MyThread("线程2"); MyThread myThread3=new MyThread("线程3"); myThread1.start(); myThread2.start(); myThread3.start(); System.out.println("myThread1 id ="+myThread1.getId()); System.out.println("myThread1 id ="+myThread2.getId()); System.out.println("myThread1 id ="+myThread3.getId()); } }

 

控制台输出截图如下,

你不知道的Runnable接口,深度解析Runnable接口

开启了三个线程。

PS:如果你也是使用Android Studio,控制台中文输出可能是乱码,那么可以参考这篇文章去解决,Android Studio中Java控制台中文输出乱码

2、实现Runnable接口。

      Runnable只是一个接口,它里面只有一个run()方法,没有start()方法,

 

 public interface Runnable{ public void run(); } 

      所以,即使实现了Runnable接口,那也无法启动线程,必须依托其他类。

 

      而Thread类,有一个构造方法,参数是Runnable对象,也就是说可以通过Thread类来启动Runnable实现多线程。

 

 public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }

      所以,实现Runnable接口后,需要使用Thread类来启动。
下面还是上案例说明,

 

创建一个类MyRunnable,实现Runnable接口,

 

public class MyRunnable implements Runnable { private String name; public MyRunnable(String name) { this.name = name; } @Override public void run() { System.out.println("MyRunnable is " + name); } }

和继承Thread类的实现方法基本一样,其实Thread类也是实现了Runnable接口,

 

你不知道的Runnable接口,深度解析Runnable接口

下面是调用以及启动线程并打印线程的id,启动线程还是调用Thread类的start()方法,

 

public class Test1 { public static void main(String[] args){ MyRunnable myRunnable1=new MyRunnable("Runnable1"); MyRunnable myRunnable2=new MyRunnable("Runnable2"); MyRunnable myRunnable3=new MyRunnable("Runnable3"); Thread myThread1=new Thread(myRunnable1); myThread1.start(); System.out.println("myThread1 id ="+myThread1.getId()); Thread myThread2=new Thread(myRunnable2); myThread2.start(); System.out.println("myThread1 id ="+myThread2.getId()); Thread myThread3=new Thread(myRunnable3); myThread3.start(); System.out.println("myThread1 id ="+myThread3.getId()); } } 

 

控制台输出截图如下,

你不知道的Runnable接口,深度解析Runnable接口

可以看到,启动了三个不同的线程。

小结:通过上面的两个小例子程序,我们可以得知,只是实现Runnable接口,并不能启动或者说实现一个线程。Runnable接口,并不能代表一个线程。Runnable接口和线程是两个不同的概念!

换句话说,一个类,实现Runnable接口,这个类可以做很多事情,不仅仅只被用于线程,也可以用于其他功能!

二、 为何明显使用Handler的post(Runnable),最终还是在主线程中执行呢?

1.我们都知道使用Handler更新UI,有时候会调用 Handler.post()方法更新UI, Handler.post()方法的源码如下,

 

 public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }

 

getPostMessage()方法是创建一个Message对象,并且将参数的Runnable对象赋值给了该Message对象的callback属性,

 

 private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }

sendMessageDelayed()方法内部会继续调用其他方法(此处不再详说),而这一系列的方法最终的功能是,将创建的Message对象加入到消息队列中。详情请看 Android 源码解析Handler处理机制(二)

 

2.执行Looper.loop()方法,该方法将会从消息循环中循环取出消息,取出消息后,会执行下面的代码,

 

 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }

参数是消息队列取出的消息,如果该消息的callback属性(Runnable对象)等于‘null’,则会执行handleMessage()方法,否则,将执行handleCallback()方法,我们重点看看handleCallback()方法,有关handleMessage()详情请看Android 源码解析Handler处理机制(二)。

 

 

 private static void handleCallback(Message message) { message.callback.run(); }

通过上面的分析,这一块是不是更加清晰、明白了!

message.callback.run();

很显然该方法仅仅是执行了消息的callback属性(Runnable对象)的run()方法,并没有开启子线程,它其实还是运行在Handler所在的线程即主线程中。

 

小结:使用Handler.post()方法更新UI,只是将消息加入到消息队列,并且设置消息的callback属性为参数Runnable对象的值;从消息循环中取出消息时,将执行消息对象的callback属性(Runnable对象)run()方法,还是在Handler所在的主线程中运行的,并没有开启新的子线程。

总结:读过本篇文章后,相信读者对Handler.post()方法更新UI理解会更清晰、完整、透彻,并且对Runnable接口会有新的不一样的认识。

 

PS:在使用Runnable时,可能会内存泄露。Runnable是一个匿名内部类,因此它对当前Activity有一个隐式引用。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。那么该怎么解决这种问题呢?代码如下,

 

 static class MyRunnable implements Runnable { @Override public void run() { //执行任务 } }

使用 静态内部类,避免了Activity的内存资源泄漏。

 

 

推荐文章:Android 更新UI的几种方法。

                 Android 源码解析Handler处理机制(一)。

                Android 源码解析Handler处理机制(二)。

欢迎大家关注我的公众号

你不知道的Runnable接口,深度解析Runnable接口

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/200244.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午11:14
下一篇 2026年3月20日 上午11:14


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号