应该同步哪些代码块?

时间:2015-07-10 12:40:00

标签: java spring synchronization synchronized managed-bean

我有三个不同的类:

  1. 托管bean(singleton范围)
  2. 托管bean(session范围)
  3. 春天@Controller
  4. 我在这里看了几篇关于同步的帖子,但我仍然不明白它应该如何以及如何运作。

    简短的例子:
    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;
        }
    }
    

    那么,它应该如何?

    抱歉我的英文。

2 个答案:

答案 0 :(得分:3)

在您发布的代码中 - 没有特别需要同步,并且您定义的同步块不会保护您免受任何伤害。您的控制器范围默认为单例。

如果您的单身人士更改了共享对象(大多数只是他们的字段),那么您应该将整个方法标记为已同步。

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

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

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

运气。

答案 1 :(得分:1)

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

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

同样在categoryService.initCategories()中调用deleteCategory()可能意味着您正在重新加载整个列表,这不是一个好主意,特别是如果您有许多类别。

相关问题