簡體   English   中英

使Java設置線程安全

[英]Make Java set threadsafe

我正在Volley的onResponse回調中更新一個集合,如下所示:

@Override
public void onResponse(String response)
{
    if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND))
    {
        if (user.getFavoriteProducts().contains(product.getId()))
        {
            user.getFavoriteProducts().remove(product.getId());

        } else {
            user.getFavoriteProducts().add(product.getId());
        }

        mSharedPreferencesManager.insertUser(user);
    }
}

當同時收到兩個響應時,將同時訪問該集合。 我正在嘗試使此設置線程安全,但是我無法使其正常工作,這是到目前為止我已經嘗試過的方法:

使用SynchronizedSet:

user.setFavoriteProducts(Collections.synchronizedSet(new HashSet<Long>()));

使用CopyOnWriteArraySet:

user.setFavoriteProducts(new CopyOnWriteArraySet<Long>());

同步回調中​​的代碼:

private static final Object object = new Object();

@Override
public void onResponse(String response)
{
    synchronized (object)
    {
        if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND))
        {
            if (user.getFavoriteProducts().contains(product.getId()))
            {
                user.getFavoriteProducts().remove(product.getId());

            } else {
                user.getFavoriteProducts().add(product.getId());
            }

            mSharedPreferencesManager.insertUser(user);
        }
    }
}

這些都不起作用,任何幫助將不勝感激!

編輯 :什么是行不通的是只插入一個項目。


編輯2 :我嘗試過N0un的方法,但仍然只插入一項

這是我使用的代碼:

@Override
public void onResponse(final String response)
{
    Log.d(Properties.TAG, "[REST_CLIENT] Response received: " + response);

    AsyncTask.execute(new Runnable()
    {
        @Override
        public void run()
        {
            synchronized (RestClient.class)
            {
                if (!response.equals(Properties.PRODUCT_NOT_FOUND) || !response.equals(Properties.USER_NOT_FOUND))
                {
                    if (user.getFavoriteProducts().contains(product.getId()))
                    {
                        Log.d(Properties.TAG, "[REST_CLIENT] Removing product from favorites: " + product.getId());
                        user.getFavoriteProducts().remove(product.getId());

                    } else {
                        Log.d(Properties.TAG, "[REST_CLIENT] Adding product to favorites: " + product.getId());
                        user.getFavoriteProducts().add(product.getId());
                    }

                    Log.d(Properties.TAG, "[REST_CLIENT] Updating user");
                    mSharedPreferencesManager.insertUser(user);

                    Log.d(Properties.TAG, "[REST_CLIENT] Set size: " + user.getFavoriteProducts().size());
                }
            }
        }
    });
}

這些是我得到的日志:

D/CUOKA: [REST_CLIENT] Response received: ACCEPTED
D/CUOKA: [REST_CLIENT] Adding product to favorites: 3921
D/CUOKA: [REST_CLIENT] Updating user
D/CUOKA: [REST_CLIENT] Response received: ACCEPTED
D/CUOKA: [REST_CLIENT] Set size: 1
D/CUOKA: [REST_CLIENT] Adding product to favorites: 2361
D/CUOKA: [REST_CLIENT] Updating user
D/CUOKA: [REST_CLIENT] Set size: 1

編輯3 :這是將用戶插入到SharedPreferences中的代碼:

public synchronized boolean insertUser(final User user)
{
    mEditor = mSharedPreferences.edit();

    Gson gson = new Gson();
    String json = gson.toJson(user);

    mEditor.putString(KEY_USER, json);

    return mEditor.commit();
}

好吧,使用經典的Java Executor在UI線程中調用Volley的偵聽Executor 我認為有一種機制可以在UI線程中有太多工作時取消一些偵聽器調用。

試試看:

@Override
public void onResponse(String response)
{
    AsyncTask.execute(new Runnable() {

        @Override
        public void run()
        {
            synchronized (MyClassName.class) {
                if (!response.equals(Properties.PRODUCT_NOT_FOUND)
                        || !response.equals(Properties.USER_NOT_FOUND)) {
                    if (user.getFavoriteProducts().contains(product.getId())) {
                        user.getFavoriteProducts().remove(product.getId());

                    } else {
                        user.getFavoriteProducts().add(product.getId());
                    }

                    mSharedPreferencesManager.insertUser(user);
                }
            }
        }
    });
}

也請參閱以下響應: 此處此處了解更多說明。

只需將在偵聽器內部執行的數據處理移至后台線程/ AsyncTask,以釋放UI線程並防止阻塞。

編輯:經過一些討論和代碼審查,我發現(第二個)問題:在請求之前已檢索user ,並且線程安全性問題在這里。 在進行新請求時,尚未保存user的數據。 因此,第二個請求與第一個請求在同一Set上工作,而不在新的更新Set 因此,應該在我建議的synchronized塊中檢索user ,然后再進行其他處理。

偵聽器正在使用Main Thread (UI線程),因此可能正在發生某種阻塞。 您應該將數據處理移至后台線程或使處理異步。

關於Set同步,您應該使用ConcurentHashMap並使用newSetFromMap()方法簡單地包裝Set。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM