防止并发回调代码运行两次

时间:2013-12-17 09:53:38

标签: java multithreading

以下代码在新线程内运行。

private class SaveUserTask extends AsyncTask<User, Void, Void> {

        @Override
        protected Void doInBackground(User... users) {
            DatabaseHandler dbHandler = new DatabaseHandler(LoginActivity.this);
            dbHandler.createUser(users[0]);
            return null;
        }

}

构造它并运行它的代码在回调方法中。

private class GraphCallbackHandler implements Request.GraphUserCallback {

        @Override
        public void onCompleted(GraphUser gUser, Response response) {
            if (gUser != null) {
                id = gUser.getId().trim();
                DatabaseHandler dbHandler = new DatabaseHandler(
                        LoginActivity.this);
        if (!dbHandler.isFacebookIdAlreadyStored(id)) {
                    SaveUserTask suTask = new SaveUserTask();
            User user = new User();
            user.setUsername(gUser.getUsername().trim());
            user.setFacebookId(id);
            if (email != null)
            user.setEmail(emailStr.trim());
            suTask.execute(user);
       }
    }

看起来两次调用回调方法会导致两个相同的行插入表中。有没有办法阻止回调方法被调用两次(这对我来说似乎不太可能实现)或停止后台任务运行两次?

2 个答案:

答案 0 :(得分:2)

只需执行以下步骤:

  1. 将您的用户存在检查代码移至doInBackground方法。
  2. 通过doInBackground LOCK设置synchronized方法代码Object
  3. 或者您可以将已保存的用户存储到内存中HashSet之类的对象,并在插入db之前检查是否存在。

    请注意,在这种情况下使用数据库的某些位置必须是线程安全的或同步的。否则,你可能会遇到这样的问题。

答案 1 :(得分:1)

如果onCompleted在短时间内拨打两次,我认为你只有一个典型的竞争条件: 快乐的道路:

  1. 检查用户不存在(thread1)
  2. 在另一个线程(thread1)中启动插入
  3. 插入(thread2)
  4. 检查用户不存在(thread1) - &gt;什么都不做
  5. 并且它可以在另一个顺序中工作,因为线程并行工作:

    1. 检查用户不存在(thread1)
    2. 在另一个线程(thread1)中启动插入
    3. 检查用户不存在(thread1)
    4. 在另一个线程(thread1)中启动插入
    5. 插入(thread2)
    6. 插入(thread3)
    7. 我认为最好的解决方案是移动(或复制)支票,以便异步操作应该进行检查以进行操作idempotent