Runnable不是要开线程跑



这是由一个故事引起的.

故事主人公发了一个帖子:

求解决android.os.NetworkOnMainThreadException
http://www.eoeandroid.com/thread-325472-1-1.html

这位楼主找到这个问题,然后明白在新版本里不应该在主线程里面做网络操作.

于是楼主找到了这篇ice的blog:

解决android.os.NetworkOnMainThreadException
http://my.eoe.cn/iceskysl/archive/4382.html

于是楼主的问题来了,"我明明根据这篇帖子提示的用runnable来做,怎么还有问题?"

我看了下,ice的代码是这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.share_mblog_view);
    new Thread(runnable).start();
}

Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Bundle data = msg.getData();
        String val = data.getString("value");
        Log.i("mylog","请求结果-->" + val);
    }
}

Runnable runnable = new Runnable(){
    @Override
    public void run() {
        //
        // TODO: http request.
        //
        Message msg = new Message();
        Bundle data = new Bundle();
        data.putString("value","请求结果");
        msg.setData(data);
        handler.sendMessage(msg);
    }
}

楼主的代码是这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
hdnet = new Handler();
 rbnet = new Runnable() {
@Override
   public void run() {
    // TODO Auto-generated method stub
 try {
      int idnum = get_maxid();

    String recv_msg = "" + idnum;
   enet =  readContentFromPost(recv_msg, RECV_TYPE);
  } catch (Exception e) {

   e.printStackTrace();
     }
  }
  };
hdnet.post(rbnet);

先不说这个代码的问题,继续看回答.

一楼告诉楼主应该:new Thread(rbnet).start();这样
楼主反问道:我的的runnable可以启动。还需要用thread?

这里就回到我要说的主题了:
谁告诉你Runnable就是要开线程跑了?

或许很多人在学多线程的时候,老师就会跟他说:Java中创建多线程有两种方式,第一种是继承Thread类,第二种是实现Runnable接口.
前者是MyThread().start();来启动新线程,后者是new Thread(myRunnable).start();来启动新线程.

久而久之,大家接触到更多的线程运行方法就是后者,然后
理所当然地认为:Runnable就代表线程,没有别的用途.

错,很错,大错特错!

很多人根本没有想过,Runnable到底是个什么?

其实
它只是一个简单的接口,只定义了一个run方法,仅此而已,源码很简单:

1
2
3
public interface Runnable {
    public abstract void run();
}

这跟我们平时定义的各种回调方法一个样,比如:

1
2
3
public interface MyCallback {
   public abstract void onComplete();
}

光从Java语言的角度看Runnable,这只是一个再简单不过了的一个很小的interface.

那,为什么Runnable多用于线程方面?
这是
因为Java不支持多重继承,很多时候你的一个class早就继承了一个父类,无法再继承Thread类,所以**大都用实现Runnable接口来做的**(实际上,Thread也是实现了Runnable接口),一个线程start执行起来,他会去找到对应的run方法然后执行它的代码.

但是,线程会执行这个Runnable中的run方法,并不是说:这个Runnable中的run方法,只会在多线程中执行!记住,它只是一个接口方法,仅此而已.难道说,
喝水都用杯子,杯子就只能用来喝水了?特殊情况下用杯子装饭吃,你还要说现在杯子里面是水么?

所以说,Runnable只是一个恰好被Thread用到,大家都用它来跑多线程的,并不能想当然的以为,它出现就必须是多线程

下面是一个例子(不推荐):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Test {
    private Runnable mRunnable;
    Test(Runnable runnable){
        this.mRunnable = runnable;
    }
    public void say(){
        mRunnable.run();
    }

    public static void main(String args[]){
        System.out.println("Main thread,pid is:"+Thread.currentThread().getId());
        new Test(new Runnable(){
            @Override
            public void run() {
                System.out.println("I am running in the main thread,not other threads,thread id is:"+Thread.currentThread().getId());
            }

        }).say();

        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("I am running in a new thread,not other main thread,thread id is:"+Thread.currentThread().getId());
            }
        }).start();
    }
}

我这里故意用到这个Runnable接口去做一个简单的输出,对比一个Thread用这个Runnable做多线程输出

运行结果:

1
2
3
Main thread,pid is:1
I am running in the main thread,not other threads,thread id is:1
I am running in a new thread,not the main thread,thread id is:8

很显然,并不是所有在Runnable中的run方法中跑的代码都是开了线程跑的,开不开线程,看的是这个Runnable有没有被一个Thread对象构造使用

其实,
回归到Android,为什么说Handler能刷新主线程UI?就算你是在其他线程post的一个runnable,最终还是在主线程中执行呢?

这是因为这个runnable,你只能当他是一个简单的对象而已,只不过是带着一个run方法的对象,当别人需要执行你的逻辑的时候再去调用你的run方法,即可.而***不是所谓的把子线程并到主线程中执行***(的确有听过人这么说的).

Handler一直在main thread中执行,有一个不断循环的Looper,不断检索一个容器MessageQueue,这个容器,一旦有Message进来就去执行这个Message,如果这个Message有callback(一个Runnable,如果是handler.post(runnable)的话, 会生成一个Message对象,这个对象的callback参数被赋值成这个runnable对象),那么也去执行这个callback(也就是runnable对象)的run方法(这个就很类似我上面例子中的Test类中的Say方法了,仅仅只是调用这个run方法而已,不是去开线程).

直接看代码更明确一点:

post一个runnable

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

实际上是生成一个Message,这个Message对象的callback参数赋值为这个runnable对象

1
2
3
4
5
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

Looper中有一个无限循环,MessageQueue中一旦有新的消息,就去调用这个消息的dispatchMessage方法:

1
2
3
4
5
6
7
8
for (;;) {
   Message msg = queue.next(); // might block
      if (msg == null) {
          return;
      }

  msg.target.dispatchMessage(msg);
//余下很多不用写,只看这个关键代码

看看dispatchMessage方法,因为之前这个Message的callback实际上就是post过来的runnable对象,所以会执行到handleCallback(msg)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

最后:

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

很显然,这个,
仅仅只是执行了这个callback(post过来的runnable对象)的run方法,没有什么多线程,所以还是在主线程中运行的.

不知道为什么Android要这么设计,导致很多人根本就搞不懂了为什么Runnable不代表用多线程来跑,但是,既然这么设计了,那就得深入的弄懂他,不要被迷惑了.

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: fortianwei

原文地址: http://my.eoe.cn/fortianwei/archive/23115.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,可以使用多线程来并发执行for循环。这样可以提高程序的执行效率,特别是在需要处理大量数据或者耗时操作时。下面是一个简单的示例代码,展示了如何使用多线程来for循环: ```java public class MultiThreadedForLoop { public static void main(String[] args) throws InterruptedException { int start = 1; int end = 100; int numThreads = 4; // 假设使用4个线程 int step = (end - start + 1) / numThreads; // 每个线程处理的步长 Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { int threadStart = start + i * step; int threadEnd = (i == numThreads - 1) ? end : threadStart + step - 1; threads[i] = new Thread(new ForLoopRunnable(threadStart, threadEnd)); threads[i].start(); } for (int i = 0; i < numThreads; i++) { threads[i].join(); // 等待所有线程执行完毕 } System.out.println("All threads have finished executing."); } } class ForLoopRunnable implements Runnable { private int start; private int end; public ForLoopRunnable(int start, int end) { this.start = start; this.end = end; } @Override public void run() { for (int i = start; i <= end; i++) { // 在这里执行你的for循环体代码 System.out.println("Thread " + Thread.currentThread().getId() + ": " + i); } } } ``` 上述代码中,我们首先定义了一个`MultiThreadedForLoop`类作为入口类。在`main`方法中,我们指定了循环的起始值`start`和结束值`end`,以及要使用的线程数`numThreads`。然后,我们计算出每个线程需要处理的步长`step`。 接下来,我们创建了一个长度为`numThreads`的线程数组`threads`,并使用循环创建了每个线程。每个线程都有自己的起始值`threadStart`和结束值`threadEnd`,确保每个线程处理不同的循环范围。我们将每个线程都传入一个自定义的`ForLoopRunnable`实例,并启动线程。 在`ForLoopRunnable`类中,我们实现了`Runnable`接口,并重写了`run`方法。在`run`方法中,我们执行了具体的for循环体代码。这里只是简单地打印了当前线程的ID和循环变量的值,你可以根据实际需求修改为你自己的代码。 最后,在主线程中,我们使用`join`方法等待所有线程执行完毕,并输出一条提示信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值