【问题标题】:Which blocks of code should be synchronized?应该同步哪些代码块?
【发布时间】:2015-07-10 12:40:00
【问题描述】:

我有三个不同的班级:

  1. 托管 bean(singleton 范围)
  2. 托管 bean(session 范围)
  3. 弹簧@Controller

我在这里阅读了一些关于同步的帖子,但我仍然不明白它应该如何以及它是如何工作的。

简短示例:
1) 托管 bean(singleton 范围)。
在这里,所有用户的所有类字段都应该相同。所有用户都使用此对象的一个​​实例或他的副本(???)。

    public class CategoryService implements Serializable {
private CategoryDao categoryDao;
private TreeNode root; //should be the same for all users
private List<String> categories = new ArrayList<String>();//should be the same for all users
private List<CategoryEntity> mainCategories = new ArrayList<CategoryEntity>();
//should be the same for all users

public void initCategories() {
    //get categories from database
}

public List<CategoryEntity> getMainCategories() {
    return mainCategories;
}}  

2) 托管 bean(session 范围)
在这种情况下,每个用户都有自己的对象实例。
当用户尝试删除类别时,他应该检查是否有其他用户尝试删除相同的类别,所以我们需要使用synchronized 阻止???

public class CategoryServiceSession implements Serializable {
private CategoryDao categoryDao;
private CategoryService categoryService;

private TreeNode selectedNode;

public TreeNode getSelectedNode() {
    return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
    this.selectedNode = selectedNode;
}

public void deleteCategory() {
    CategoryEntity current = (CategoryEntity) selectedNode.getData();

    synchronized (this) {
        //configure tree
        selectedNode = null;
        categoryDao.delete(current);
    }
    categoryService.initCategories();
}}  

3) 春天@Controller
这里所有用户都可能有一个实例(或者每个用户都有他自己的实例???)。但是当某些管理员尝试更改某些用户的参数时,他应该检查是否有其他管理员尝试执行相同的操作??

@Controller
@RequestMapping("/rest")
public class UserResource {
   @Autowired
   private UserDao userDao;

   @RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
    public @ResponseBody UserEntity changeBannedStatus(@PathVariable Long id) {
        UserEntity user = userDao.findById(id);
        synchronized (id) {
           user.setBanned(!user.getBanned());
           userDao.update(user);
        }
    return user;
    }
}

那么,它应该是怎样的呢?

对不起我的英语。

【问题讨论】:

    标签: java spring synchronization synchronized managed-bean


    【解决方案1】:

    在您发布的代码中 - 没有什么特别需要同步,您定义的同步块不会保护您免受任何事情的影响。默认情况下,您的控制器范围是单例的。

    如果您的单例更改共享对象(主要是它们的字段),那么您可能应该将整个方法标记为已同步。

    方法级变量和最终参数可能永远不需要同步(至少在您似乎正在使用的编程模型中)所以不用担心。

    会话对象主要由序列化保护,但如果您的用户有并发请求,您仍然可以进行数据竞争——您必须想出创造性的方法来处理这个问题。

    您可能/将会在数据库中遇到并发问题(多个用户尝试同时删除或修改数据库行),但这应该通过您的 DAO 中的悲观或乐观锁定和事务策略来处理。

    运气。

    【讨论】:

    • 因此,如果两个进程试图更改相同的user 这段代码synchronized (id) { userDao.update(user); } 是否有助于避免冲突/错误?
    • 没有。因为任何给定的“用户”实例都是本地的,并且用户对象与 id 对象不同。你在这里混淆了很多概念。
    【解决方案2】:

    一般来说,在代码中使用synchronized 语句会降低可伸缩性。如果您曾经尝试使用多个服务器实例,那么您的 synchronized 很可能毫无用处。事务语义(使用乐观或悲观锁定)应该足以确保您的对象保持一致。所以在 2 和 3 中你不需要那个。

    至于CategoryService 中的共享变量也许可以同步,但你的categories 似乎是某种缓存。如果是这种情况,您可能会尝试使用持久性提供程序的缓存(例如,在 Hibernate 中,二级缓存或查询缓存)或数据库的缓存。

    同时在deleteCategory() 中调用categoryService.initCategories() 可能意味着您正在重新加载整个列表,这不是一个好主意,尤其是在您有很多类别的情况下。

    【讨论】:

      猜你喜欢
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 1970-01-01
      • 2012-11-06
      • 2012-01-17
      相关资源
      最近更新 更多