SharedPreferences和线程安全

cot*_*aws 48 android thread-safety sharedpreferences

查看SharedPreferences文档,它说:

"注意:目前这个类不支持跨多个进程使用.这将在以后添加."

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

例如:

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

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

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

Kev*_*oil 87

进程和线程是不同的.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;
            }
        }
    ...
    }
}
Run Code Online (Sandbox Code Playgroud)

但是对于你的唯一id的情况,似乎你仍然想要同步,因为你不希望它在get和put之间改变.

  • 尽管`SharedPreferencesImpl`被认为是线程安全的并且每个文件使用一个进程唯一的单例,但重要的是要注意它的用法本质上不是原子的:当两个编辑器同时修改首选项时,最后一个调用`commit ()`或`apply()`获胜,根据[SharedPreferences.Editor](http://developer.android.com/reference/android/content/SharedPreferences.Editor.html)文档. (10认同)

Ric*_*ier 6

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

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


我已经查看了Android 14代码进行检查,并且它非常复杂.特别SharedPreferencesImpl是在读取和写入磁盘时似乎使用不同的锁:

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

我不相信这段代码真的很安全.