54

查看SharedPreferences 文档,它说:

“注意:目前这个类不支持跨多个进程使用,这个会在以后增加。”

所以它本身似乎不是线程安全的。但是,对于 commit() 和 apply() 做了什么样的保证?

例如:

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

在这种情况下,是否可以保证 uniqueId 始终是唯一的?

如果没有,是否有更好的方法来跟踪持续存在的应用程序的唯一 ID?

4

4 回答 4

96

进程和线程是不同的。Android 中的 SharedPreferences 实现是线程安全的,但不是进程安全的。通常,您的应用程序将在同一个进程中运行,但您可以在 AndroidManifest.xml 中对其进行配置,例如,服务运行在与活动不同的进程中。

要验证线程安全性,请参阅 AOSP 中的 ContextImpl.java 的 SharedPreferenceImpl。请注意,在您期望的任何地方都有一个同步的。

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

但是,对于您的唯一 id 的情况,您似乎仍然需要同步,因为您不希望它在 get 和 put 之间发生变化。

于 2011-01-14T20:25:13.327 回答
7

我想知道同样的事情 - 并遇到这个线程说它们不是线程安全的:

Context.getSharedPreferences() 和 Editor.commit() 的实现不在同一个监视器上同步。


从那以后,我查看了要检查的 Android 14 代码,并且涉及很多。特别SharedPreferencesImpl是在读写磁盘时似乎使用了不同的锁:

  • enqueueDiskWrite()锁定mWritingToDiskLock
  • startLoadFromDisk()锁定this,并启动线程锁定SharedPreferencesImpl.this

我不相信这段代码真的是安全的。

于 2012-08-27T12:21:27.233 回答
4

我认为那会做到的。

您可以在同步部分中使用 sleep 对其进行测试,并从不同的线程中调用它

于 2011-01-14T16:47:54.617 回答
4

您应该知道 SharedPreferences 不适用于三星手机,请查看android 问题

我已经实现了简单的数据库首选项存储,您可以在github上找到它。

干杯,

于 2011-09-07T12:21:32.700 回答