我正在像这样更新 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();
}
最佳答案
好吧,Volley 的监听器是在 UI 线程中使用经典的 Java 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);
}
}
}
});
}
Simply move that data processing that is performed inside your listeners to a background thread / AsyncTask to free your UI thread and prevent the blocking.
编辑: 经过一些讨论和代码审查,我发现了(第二个)问题:user
在请求之前被检索,线程安全问题就在这里。在处理新请求时,用户
的数据尚未保存。因此,第二个请求在与第一个请求相同的 Set
上工作,而不是在新更新的 Set
中。所以 user
应该在我建议的 synchronized
block 中检索,然后再进行其他处理。
关于java - 使Java设置线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41207959/