Общие действия и безопасность потоков

Глядя на Документы SharedPreferences, он говорит:

"Примечание: в настоящее время этот класс не поддержка поддержки нескольких процессов. Это будет добавлено позже.

Таким образом, сам по себе он не является Thread Safe. Однако какие гарантии предоставляются в отношении commit() и apply()?

Например:

synchronized(uniqueIdLock){
   uniqueId = sharedPreferences.getInt("UNIQUE_INCREMENTING_ID", 0);
   uniqueId++;
   sharedPreferences.edit().putInt("UNIQUE_INCREMENTING_ID", uniqueId).commit();
}

Будет ли гарантировано, что uniqueId всегда был уникальным в этом случае?

Если нет, есть ли лучший способ отслеживать уникальный идентификатор для сохраняемого приложения?

Ответ 1

Процессы и потоки разные. Реализация SharedPreferences в Android является потокобезопасной, но не безопасной для процесса. Обычно ваше приложение будет запускать все в одном процессе, но вы можете настроить его в AndroidManifest.xml, так что, скажем, служба запускается в отдельном процессе, чем, скажем, активность.

Чтобы проверить безопасность thready, см. ContextImpl.java SharedPreferenceImpl от AOSP. Обратите внимание, что там синхронизировано, где бы вы ни ожидали, что он будет таким.

private static final class SharedPreferencesImpl implements SharedPreferences {
...
    public String getString(String key, String defValue) {
        synchronized (this) {
            String v = (String)mMap.get(key);
            return v != null ? v : defValue;
        }
   }
...
    public final class EditorImpl implements Editor {
        public Editor putString(String key, String value) {
            synchronized (this) {
                mModified.put(key, value);
                return this;
            }
        }
    ...
    }
}

Однако для вашего случая с уникальным идентификатором кажется, что вы все равно хотите синхронизировать, так как вы не хотите, чтобы он менялся между get и put.

Ответ 2

Вы должны знать, что SharedPreferences не работают на телефонах Samsung, посмотрите проблему Android.

Я реализовал простое хранилище настроек базы данных, которое вы можете найти на github.

Приветствия,

Ответ 3

Мне было интересно то же самое - и наткнулся на этот поток, который говорит, что они не являются потокобезопасными:

Реализации Context.getSharedPreferences() и Editor.commit() не синхронизируются на одном мониторе.


С тех пор я просмотрел код Android 14 для проверки, и он очень востребован. В частности, SharedPreferencesImpl, по-видимому, использует разные блокировки при чтении и записи на диск:

  • enqueueDiskWrite() блокировки на mWritingToDiskLock
  • startLoadFromDisk() блокирует this и запускает блокировку потока на SharedPreferencesImpl.this

Я не убежден, что этот код действительно безопасен.

Ответ 4

Я думаю, что это сделает.

Вы можете протестировать его с помощью сна внутри синхронизированного раздела и вызвать его из разных потоков