0

I am trying to avoid executing duplicate tasks on a Service by using a synchronised Map in the onStartMethod and then checking that a key is not already stored. However, so far is not working, it is executing the same thing twice if I call start the service twice soon enough.

public void onCreate() {
           SYNCED_TABLES = Collections.synchronizedMap(new Hashtable<>());
}
public int onStartCommand(Intent intent, int flags, int startId) {
           synchronized (SYNCED_TABLES){
                if(!SYNCED_TABLES.containsKey(intent.getStringExtra(KEY))){
                    SYNCED_TABLES.put(intent.getStringExtra(KEY), true);
                    /* Do stuff on a Handler thread */
                }
                else{
                    Log.d(TAG, "Tried to execute the same task twice " + intent.getStringExtra(KEY));
                }
            }

}
Julio
  • 283
  • 2
  • 13

1 Answers1

0

The initialization of SYNCED_TABLES is not thread safe. As a consequence you risk having multiple objects assigned to this field on which you lock, i.e. you have multiple locks.

Declare SYNCED_TABLES as a final field and initialize it right there:

public class Foo {
    final SYNCED_TABLES = Collections.synchronizedMap(new Hashtable<>());
}

This guarantees that you have a single lock over the lifetime of your object.

aha
  • 3,702
  • 3
  • 38
  • 47
  • It works, but, after the Service is dead, does the map is instantiated again? Because I just tried to run the service again after a few minutes and it did not execute because the old values were still stored. – Julio Feb 15 '17 at 19:34
  • There's https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#clear() to empty the collection. You could call that in `onCreate()` if that fits your needs. – aha Feb 15 '17 at 20:59