Why does one background thread have the same thread id as the main service thread?

Trying to create 2 background threads and post a message from thread0 to thread1 where it is handled by a MessageHandler using the android Looper and the message queue associated with thread1.

I was expecting to see separate thread IDs for threads 0,1 and the main thread. However, I was surprised to see something unexpected.

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

      

Why does BackgroundThread1 have the same thread id as the main service thread id = 1?

I install it from Eclipse using Run As and run it in a windows console window:

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 }

      

- package 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>

      

Out of eclipse, DDMS window

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  

      

After executing the below TacBoss suggestion, I get thread id = 450 which is expected. thread id 451 is probably finished.

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

      

- code changes

    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;
    }

      

0


source to share


2 answers


OK it didn't show up ...

the problem is that you are creating a handler inside BGThread1's constructor and this code is called from the main thread! and therefore the handler queue is also bound to the main thread.

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

      

If you want this handler to run on a different thread, you first need to do something like this:

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!
    }
    ...
}

      



This will create a thread in the context you expect from it.

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

An example of extending a "regular" stream:

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();
    }
}

      

The handler now runs on a new thread.

+1


source


This is because the lifecycle is Service

handled in the main thread, that is: Service

methods such as onCreate

, onStartCommand

are onDestruction

called on the main thread by default, as explained in the second paragraph android.app.Service Class Overview



Note that services, like other application objects, run on the main hosting thread.

+1


source