Domanda

In other words, to my understanding, this is not thread safe (for multiple calls of startService()):

public class RaceService extends Service {

    volatile int a; // edit: added volatile to clarify my point

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                a++;
                Log.w("RaceService", "a: " + a);
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
}

because there is only one instance of the service created (although never managed to find a clear assertion for this - if anyone could point me to the source where the service is actually instantiated (by reflection?) I would appreciate it). If one instance were created per startService() this would just print 1 on every call of startService.

But is this:

public class RaceService2 extends Service {

    int a;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        a++;
        Log.w("RaceService2", "a: " + a);
        return super.onStartCommand(intent, flags, startId);
    }
}

thread safe (for multiple calls of startService()) ?

Would using an IntentService make a difference in these two examples (where the code would be in onHandleIntent()) ?

È stato utile?

Soluzione

It's the same as the need for synchronization anywhere else in Java or Android - if you have multiple threads accessing the variables you may need synchronized methods to prevent thread interference or you may need to declare the variables as volatile so that each thread gets an up to date copy.

The only thing Android specific to note is that the onStartCommand is going to be called by the system on the main thread, so you are blocking the main UI thread unless you make it otherwise. If you use IntentService the onHandleIntent method is called on a different thread, so you can offload your long running task there without worrying about the mechanics of creating and using a separate thread.

A place where you might use a volatile instance variable would be if mutate a variable in onHandleIntent, and then access it in onDestroy. Here you want to ensure you have a fresh copy when onDestroy is called.

All that can be said of your examples is that in your first example, the value of a at the Log statement is undefined, and in the second example it is 1 if this is a new object.

EDIT: The bottom line is you really shouldn't be counting on the value of instance variables to be anything if you are calling startService() multiple times (we don't know if it's even going to be the same instance since it could have been destroyed) and you shouldn't count on the order of calls to startService() to necessarily be the same as the order they executed by the service (even though that seems to be the way it's implemented).

Stuff the requests into an array and send them as one call to startService(), or use local variables within the Service if you need such guarantees.

If you a more complicated scenario with multi-threading within the Service, you should should post a concrete example of the problem, because without knowing what you're trying to it's impossible to give advice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top