[英]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.