为什么单个静态变量在多次读取时有多个值?

why single static variable has multiple values on multiple reads?

上下文:
在 Android 中,我正在尝试为所有联系人实施单一来源 DataSet<ContactEntry>。因此,当同步过程更新任何联系人时,它们应该反映在现有适配器中(仅当存在活动适配器时)。
但是,所有来自同步的 updates/additions/removals 都被忽略,因为同步总是发现 DataSet<ContactEntry> 为空(即使它不为空)。

源代码:

public class ContactsDataSet {

    private static final String TAG = "ContactsDataSet";

    private static final Object lock = new Object();
    private static volatile WeakReference<DataSet<ContactEntry>> instance = null;

    public static DataSet<ContactEntry> getInstance(Context context) {
        synchronized (lock) {
            DataSet<ContactEntry> dataSet;
            if (instance == null) {
                    Log.d(TAG, "Creating instance for ContactsDataSet");
                    dataSet = createDataSet(context);
                    instance = new WeakReference<>(dataSet);
                    Log.d(TAG, "Set instance to: " + instance + " on " + Thread.currentThread().getName());
            } else {
                dataSet = instance.get();
                if (dataSet == null) {
                    Log.d(TAG, "Re-creating Data Set");
                    dataSet = createDataSet(context);
                    instance = new WeakReference<>(dataSet);
                    Log.d(TAG, "Set instance to: " + instance + " on " + Thread.currentThread().getName());
                } else {
                    Log.d(TAG, "Valid instance: " + instance + " on " + Thread.currentThread().getName());
                }
            }
            return dataSet;
        }
    }

    public static void printInstance() {
        synchronized (lock) {
            Log.d(TAG, "printInstance() => " + instance + " on " + Thread.currentThread().getName());
        }
    }


    private static DataSet<ContactEntry> getInstance() {
        synchronized (lock) {
            DataSet<ContactEntry> ret= instance == null ? null : instance.get();
            Log.d(TAG, "getInstance() => " + instance + " on " + Thread.currentThread().getName());
            return ret;
        }
    }


    private static DataSet<ContactEntry> createDataSet(Context context) {
        Log.d(TAG, "Fetching contacts from DB");
        return new DataSet<>(DbHelper.getInstance(context).fetchValidContacts());
    }


    public static void addContact(ContactEntry contact) {
        if (contact.isDirty() || TextUtils.isEmpty(contact.getUserNumber())) {
            Log.d(TAG, "Ignoring dirty/incomplete contact");
            return;
        }
        synchronized (lock) {
            DataSet<ContactEntry> dataSet = getInstance();
            if (dataSet != null) {
                Log.d(TAG, "Adding " + contact + " to Cache");
                dataSet.addItem(contact);
            } else {
                Log.d(TAG, "Ignoring new Contact " + contact + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName());
            }
        }
    }

    public static void updateContact(ContactEntry contact) {
        if (contact.isDirty() || TextUtils.isEmpty(contact.getUserNumber())) {
            Log.d(TAG, "Removing dirty/incomplete contact");
            deleteContact(contact.getContactId());
        }
        synchronized (lock) {
            DataSet<ContactEntry> dataSet = getInstance();
            if (dataSet != null) {
                Log.d(TAG, "Updating " + contact + " in Cache");
                dataSet.updateItem(contact);
            } else {
                Log.d(TAG, "Ignoring update Contact " + contact + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName());
            }
        }
    }

    public static void deleteContact(int contactId) {
        synchronized (lock) {
            DataSet<ContactEntry> dataSet = getInstance();
            if (dataSet != null) {
                Log.d(TAG, "Removing " + contactId + " from Cache");
                dataSet.removeItem(contactId);
            } else {
                Log.d(TAG, "Ignoring delete Contact " + contactId + " as instance: " + instance + " isn't valid on " + Thread.currentThread().getName());
            }
        }
    }
}

DataSet class 是一个包含观察者列表的简单列表。

getInstance(Context context)被调用时,instance总是有一个值(当然,不是第一次)。
但是,当从任何方法 addContactupdateContactdeleteContact 调用 getInstance() 时,静态变量 instance 始终具有值 null(即使当线程名称相同时:main)。

我试过删除 Multidex 支持,使 instance 变量 volatile 但无法正常工作。任何帮助将不胜感激。提前致谢!

日志:

    When I first invoke Adapter:

    09-03 18:01:04.367 18369-18369/in.yyyyyyy.xxxxx D/ContactsAdapter: ContactsAdapter()
    09-03 18:01:04.369 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Creating instance for ContactsDataSet
    09-03 18:01:04.369 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Fetching contacts from DB
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx I/ContactEntry: fetchValidContacts() => [ContactEntry { contactId: 1, contactVersion: 4, phoneNumber: +999999999999, email: null, userNumber: 7dc5baec-1e08-43f4-b124-8d65d097036e, name: CCCCCCCCCCCCCC, dirty: false }, ContactEntry { contactId: 3, contactVersion: 3, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: GGGGGG, dirty: false }, ContactEntry { contactId: 4, contactVersion: 20, phoneNumber: +999999999999, email: null, userNumber: 7dc5baec-1e08-43f4-b124-8d65d097036e, name: MMMMMM, dirty: false }]
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Set instance to: java.lang.ref.WeakReference@90e9b43 on main
    09-03 18:01:04.398 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => java.lang.ref.WeakReference@90e9b43 on main

    Triggered Sync (after updating 3rd contact - MMMMMM):

    09-03 18:02:43.986 28748-28748/in.yyyyyyy.xxxxx:sync D/SyncContacts: Updating User Number for ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: null, name: MMMMMM, dirty: true } with 13d7b667-b523-41b7-ba89-203139e0dba9
    09-03 18:02:43.986 28748-28748/in.yyyyyyy.xxxxx:sync I/ContactEntry: updateAccount(ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: MMMMMM, dirty: false })
    09-03 18:02:43.992 28748-28748/in.yyyyyyy.xxxxx:sync D/ContactsDataSet: getInstance() => null on main
    09-03 18:02:43.992 28748-28748/in.yyyyyyy.xxxxx:sync D/ContactsDataSet: Ignoring update Contact ContactEntry { contactId: 4, contactVersion: 21, phoneNumber: +333333333333, email: null, userNumber: 13d7b667-b523-41b7-ba89-203139e0dba9, name: MMMMMM, dirty: false } as instance: null isn't valid on main


    When I invoke Adapter again:

    09-03 18:07:40.255 18369-18369/in.yyyyyyy.xxxxx D/ContactsAdapter: ContactsAdapter()
    09-03 18:07:40.257 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: Valid instance: java.lang.ref.WeakReference@90e9b43 on main
    09-03 18:07:40.257 18369-18369/in.yyyyyyy.xxxxx D/ContactsDataSet: printInstance() => java.lang.ref.WeakReference@90e9b43 on main

问题在于同步服务作为不同的进程启动。我不知道一个 Android 进程可以有多个 Linux 进程。同步服务配置:

    <service
        android:name=".sync.SyncService" android:process=":sync">
        <intent-filter>
            <action android:name="android.content.SyncAdapter" />
        </intent-filter>

        <meta-data
            android:name="android.content.SyncAdapter"
            android:resource="@xml/syncadapter" />
    </service>

我在不知道那是什么的情况下从互联网上的其他应用程序复制了该配置 android:process

我删除了属性 android:process,它开始工作了。