java - 使Java设置线程安全

标签 java android thread-safety android-volley

我正在像这样更新 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);
                }
            }
        }
    });
}

还可以查看这些回复:herehere以获得更多解释。

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/

相关文章:

java - 对于可运行存储对其自身正在运行的线程的引用有什么注意事项吗?

java - 意外 token : ( in HQL

java - GWT Maven 集成

java - 构造函数 JsonPrimitive(Object) 不可见

python - Django 和线程安全

c# - "relevant"是XmlWriterTraceListener的非线程安全性如何?

java - 在 Java 中连接多个 .txt 文件

java - 无法使用 jasper 报告在 xls 文档中显示图表

android - 隐藏抽屉导航中某些 fragment 的工具栏中的菜单图标

Android Spinner 获取选定值 OnSelectedItemListener();