为什么一个后台线程与主服务线程具有相同的线程ID?

时间:2014-09-08 17:59:34

标签: java android multithreading android-service

尝试创建2个后台线程并从thread0向thread1发送消息  由MessageHandler使用 android Looper和与thread1关联的消息队列来处理。

我希望看到线程0,1和主线程的单独线程ID。但是,我很惊讶地发现了一些意外的事情。

09-08 14:23:21.089: D/MQ(4514): Hi, the system is up! Today is: Sep 8, 2014 2:23:21 PM
09-08 14:23:21.099: V/MQ(4514): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 14:23:21.099: V/MQ(4514): BackgroundThread0. Thread id = 280 sent message 0
09-08 14:23:21.099: V/MQ(4514): MessageHandler on thread Thread id = 1 received message 0

为什么BackgroundThread1与主服务线程id = 1具有相同的线程ID?

我使用Run As从Eclipse安装它,并在Windows控制台窗口中启动它:

D:\>adb shell am startservice --user 0 -a android.intent.action.MAIN -n "com.sandbox.mq/.MainService"
Starting service: Intent { act=android.intent.action.MAIN cmp=com.sandbox.mq/.MainService }

- 包com.sandbox.mq;

public class StartMainService extends Application {
    final static String TAG = "MQ";

    public void onCreate() {
        super.onCreate();
        Context context = getApplicationContext();
        Log.d(TAG, "Hi, the system is up! Today is: " + DateFormat.getDateTimeInstance().format(new Date()));
    }
}

-

public class MainService extends Service {
    final static String TAG = "MQ";
    BackgroundThread0 bthread0;
    BackgroundThread1 bthread1;

    public class MqBinder extends Binder {
        public MqBinder(Context ctxt) {
            Log.v(TAG, "MqBinder() " + "Thread id = "
                    + Thread.currentThread().getId());
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return new MqBinder(this);
    }

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand(). I am INSIDE THE main sERVICE "
        + "Thread id = " + Thread.currentThread().getId());
bthread1 = new BackgroundThread1();
if (!bthread1.isAlive()) {
    bthread1.start();
} else {
    Log.v(TAG, "onStartCommand(). bthread1 was already started");
}
bthread0 = new BackgroundThread0();
if (!bthread0.isAlive()) {
    bthread0.start();
} else {
    Log.v(TAG, "onStartCommand(). bthread0 was already started");
}       
return START_STICKY;
}

    private class BackgroundThread0 extends Thread {
        Handler b1Handler;

        @Override
        public void run() {
            super.run();
            b1Handler = bthread1.b1Handler;
            Message msg = b1Handler.obtainMessage(MessageHandler.TYPE0);
            b1Handler.sendMessage(msg);
            Log.v(TAG, "BackgroundThread0. " + "Thread id = "
                    + Thread.currentThread().getId() + " sent message "
                    + msg.what);
        }

    }

    private class BackgroundThread1 extends Thread {
        public BackgroundThread1() {
            super();
            b1Handler = new MessageHandler();
        }

        Handler b1Handler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            Looper.loop();
        }

    }

    private static class MessageHandler extends Handler {
        static final int TYPE0 = 0;
        static final int TYPE1 = 1;
        static final int TYPE2 = 2;

        public MessageHandler() {

        }

        @Override
        public void handleMessage(Message msg) {
            Log.v(TAG, "MessageHandler on thread " + "Thread id = "
                    + Thread.currentThread().getId() + " received message "
                    + msg.what);

            switch (msg.what) {
            case TYPE0:
                break;
            case TYPE1:
                break;
            case TYPE2:
                break;
            }
            super.handleMessage(msg);
        }
    }
}

-

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sandbox.mq" >

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

    <application
        android:name="com.sandbox.mq.StartMainService"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:persistent="true"
        android:theme="@style/AppTheme" >
        <service android:name="com.sandbox.mq.MainService" android:exported="true"> 
             <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>          
        </service>        
    </application>

</manifest>

来自eclipse, DDMS 窗口

1   4514    Native  0   2   main    
*2  4518    VmWait  0   0   GC  
*3  4519    VmWait  0   0   Signal Catcher  
*4  4520    Runnable    0   2   JDWP    
*5  4521    VmWait  0   0   Compiler    
*6  4522    Wait    0   0   ReferenceQueueDaemon    
*7  4523    Wait    0   0   FinalizerDaemon 
*8  4524    Wait    0   0   FinalizerWatchdogDaemon 
9   4525    Native  0   0   Binder_1    
10  4526    Native  0   0   Binder_2    
11  4527    Native  0   0   Thread-279  

按照下面的TacBoss建议后,我得到了预期的线程ID = 450。线程ID 451可能已完成。

1   11756   Native  1   1   main    
*2  11760   VmWait  0   0   GC  
*3  11761   VmWait  0   0   Signal Catcher  
*4  11762   Runnable    0   0   JDWP    
*5  11763   VmWait  0   0   Compiler    
*6  11764   Wait    0   0   ReferenceQueueDaemon    
*7  11765   Wait    0   0   FinalizerDaemon 
*8  11766   Wait    0   0   FinalizerWatchdogDaemon 
9   11767   Native  0   0   Binder_1    
10  11768   Native  0   0   Binder_2    
11  11770   Native  0   0   Thread-450  


09-08 15:06:05.089: D/MQ(7931): Hi, the system is up! Today is: Sep 8, 2014 3:06:05 PM
09-08 15:06:05.089: V/MQ(7931): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:06.149: D/MQ(7946): Hi, the system is up! Today is: Sep 8, 2014 3:06:06 PM
09-08 15:06:06.149: V/MQ(7946): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:10.269: D/MQ(7964): Hi, the system is up! Today is: Sep 8, 2014 3:06:10 PM
09-08 15:06:10.269: V/MQ(7964): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:26.339: D/MQ(8110): Hi, the system is up! Today is: Sep 8, 2014 3:06:26 PM
09-08 15:06:26.339: V/MQ(8110): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:36.319: D/MQ(8166): Hi, the system is up! Today is: Sep 8, 2014 3:06:36 PM
09-08 15:06:36.319: V/MQ(8166): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:37.389: D/MQ(8182): Hi, the system is up! Today is: Sep 8, 2014 3:06:37 PM
09-08 15:06:37.389: V/MQ(8182): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:06:41.469: D/MQ(8200): Hi, the system is up! Today is: Sep 8, 2014 3:06:41 PM
09-08 15:06:41.469: V/MQ(8200): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:08:27.439: D/MQ(8577): Hi, the system is up! Today is: Sep 8, 2014 3:08:27 PM
09-08 15:08:27.439: V/MQ(8577): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:08:28.479: D/MQ(8593): Hi, the system is up! Today is: Sep 8, 2014 3:08:28 PM
09-08 15:08:28.489: V/MQ(8593): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:08:32.579: D/MQ(8612): Hi, the system is up! Today is: Sep 8, 2014 3:08:32 PM
09-08 15:08:32.579: V/MQ(8612): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:08:48.679: D/MQ(8630): Hi, the system is up! Today is: Sep 8, 2014 3:08:48 PM
09-08 15:08:48.679: V/MQ(8630): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:29:00.949: D/MQ(11756): Hi, the system is up! Today is: Sep 8, 2014 3:29:00 PM
09-08 15:29:00.949: V/MQ(11756): onStartCommand(). I am INSIDE THE main sERVICE Thread id = 1
09-08 15:29:00.959: V/MQ(11756): BackgroundThread0. Thread id = 451 sent message 0
09-08 15:29:00.959: V/MQ(11756): MessageHandler on thread Thread id = 450 received message 0

- 代码更改

    private class BackgroundThread1 extends Thread {
        public BackgroundThread1() {
            super();
            start();
        }

        Handler b1Handler;

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            Looper looper = Looper.myLooper();
            b1Handler = new MessageHandler(looper);
            Looper.loop();
        }

    }

        public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG, "onStartCommand(). I am INSIDE THE main sERVICE "
                + "Thread id = " + Thread.currentThread().getId());
        bthread1 = new BackgroundThread1();
//      if (!bthread1.isAlive()) {
//          bthread1.start();
//      } else {
//          Log.v(TAG, "onStartCommand(). bthread1 was already started");
//      }
        bthread0 = new BackgroundThread0();
        if (!bthread0.isAlive()) {
            bthread0.start();
        } else {
            Log.v(TAG, "onStartCommand(). bthread0 was already started");
        }       
        return START_STICKY;
    }

2 个答案:

答案 0 :(得分:1)

这是因为Service生命周期是在主线程上处理的,即:Service onCreateonStartCommandonDestruction等方法被调用默认情况下为主线程,如android.app.Service's Class Overview

的第二段所述
  

请注意,服务与其他应用程序对象一样,在其托管进程的主线程中运行。

答案 1 :(得分:1)

好的,这并没有直接弹出......

问题是你在BGThread1的构造函数中创建处理程序,并且从主线程调用此代码!这就是处理程序队列也附加到主线程的原因。

public BackgroundThread1() {
    super();
    b1Handler = new MessageHandler(); // this is the main thread here...
}

如果您希望此处理程序在另一个线程上运行,您首先必须执行以下操作:

private class BackgroundThread1 extends HandlerThread {
    public BackgroundThread1() {
        super();
         ...
          Some code
         ...
        start();
        b1Handler = new MessageHandler(getLooper()); 
            // this is the main thread here... but you create the handler with the looper of the new thread!
    }
    ...
}

这将在您期望的上下文中创建线程。

=============================================== ====

扩展&#34;常规&#34;螺纹:

class MyThread
        extends Thread {

    private Handler myHandler;

    public MyThread() {
        start();
    }

    @Override
    public void run() {
        Looper.prepare();
        Looper looper = Looper.myLooper();
        myHandler = new Handler(looper);
        Looper.loop();
    }
}

现在处理程序在新线程上运行。