What blocks of code should be in sync?

I have three different classes:

  • Bean ( singleton

    ) managed scope
  • Bean ( session

    ) managed scope
  • Spring @Controller

I have read several posts here about synchronization, but I still don't understand how it should be and how it works.

Brief examples:
1) The managed scope bean ( singleton

).

Here all class fields should be the same for all users. All users work with one instance of this object or with its copies (???).

    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) Managed scope bean ( session

)

In this case, each user has his own instance of the object.
When a user tries to delete a category he should check, it is other users who are trying to delete the same category, so we need to use synchronized

block ???

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) Spring@Controller


Here all users can have an instance (or each user has their own instance ???). But when some admin tries to change the setting of some user, should he check another admin trying to do the same operation?

@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;
    }
}

      

So how should it be?

Sorry for my English.

+3


source to share


2 answers


In the code you posted, nothing fancy needs to be synchronized, and the synchronized blocks you have defined will not protect you from anything. The default scope of your controller is singleton.

If your singletons change shared objects (mostly just their fields), then you should probably mark the entire method as synchronized.

Method level variables and final parameters will probably never need to be synchronized (at least in the programming model you seem to be using), so don't worry about that.



The session object is mostly serialized-protected, but you still have races of data, if your user has concurrent requests - you'll have to imagine creative ways to handle that.

You may / will have concurrency issues in the database (multiple users trying to delete or modify a database row at the same time), but this should be done with a pessimistic or optimistic locking and transaction policy in your DAO.

Luck.

+3


source


Generally speaking, using operators synchronized

in your code reduces scalability. If you ever try to use multiple server instances yours synchronized

will most likely be useless. Transaction semantics (using optimistic or pessimistic locking) should be sufficient to ensure that your object remains consistent. So in 2 and 3 you don't need that.

As far as shared variables in CategoryService

, it might be possible to sync it, but yours categories

seems to be a kind of cache. If so, you can try to use your continuity provider's cache (for example, in Hibernate second-level cache or query cache) or your database.



Also calling categoryService.initCategories()

in deleteCategory()

probably means that you are reloading the entire list, which is not good, especially if you have a lot of categories.

+1


source







All Articles