2015-07-10 2 views
3

У меня есть три различных класса:Какие блоки кода должны быть синхронизированы?

  1. управляемый компонент (singleton сфера)
  2. управляемый компонент (session сфера)
  3. Spring @Controller

Я прочитал несколько постов здесь о синхронизации, но я все еще не понимают, как это должно быть и как это работает.

Короткие примеры:
1) управляемый компонент (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) управляемый компонент (session сферы)
В этом случае каждый пользователь имеет свой собственный экземпляр объекта.
Когда пользователь пытается удалить категорию, которую он должен проверить, это другие пользователи, которые пытаются удалить одну и ту же категорию, поэтому нам нужно использовать 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) Пружина @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; 
    } 
} 

Итак, как это должно быть?

Извините за мой английский.

ответ

3

В коде, который вы опубликовали, ничего особенного не нужно синхронизировать, а синхронизированные блоки, которые вы определили, не будут защищать вас от чего-либо. По умолчанию объем вашего контроллера равен singleton.

Если ваши синглтоны изменяют общие объекты (в основном только их поля), то вы, вероятно, должны помечать весь метод как синхронизированный.

Переменные уровня метода и конечные параметры, вероятно, никогда не потребуют синхронизации (по крайней мере, в модели программирования, которую вы, похоже, используете), поэтому не беспокойтесь об этом.

Объект сеанса охраняется, главным образом, сериализацией, но у вас все еще есть гонки данных, если у вашего пользователя есть одновременные запросы - вам придется представить себе творческие способы справиться с этим.

У вас могут возникнуть проблемы параллелизма в базе данных (несколько пользователей, пытающихся одновременно удалять или изменять строку базы данных), но это должно решаться с помощью пессимистической или оптимистической политики блокировки и транзакций в вашем DAO.

Luck.

+0

Следовательно, если два процесса пытаются изменить один и тот же «пользователь», этот фрагмент кода «synchronized (id)] {userDao.update (пользователь); } 'не помогает избежать столкновения/ошибки? – DarkFeniks

+0

Нет. Поскольку любой данный экземпляр «пользователь» является локальным, и пользовательский объект в любом случае не совпадает с объектом id. Вы немного смешиваете понятия. – lscoughlin

1

Вообще говоря, с помощью synchronized операторов в вашем коде уменьшает масштабируемость.Если вы когда-либо пытаетесь использовать несколько экземпляров сервера, ваш synchronized будет, скорее всего, бесполезным. Семантика транзакций (с использованием оптимистической или пессимистической блокировки) должна быть достаточной для обеспечения того, чтобы ваш объект оставался согласованным. Так что в 2 и 3 вам это не нужно.

Что касается общих переменных в CategoryService, возможно, его можно будет синхронизировать, но ваш categories кажется каким-то кешем. Если это так, вы можете попытаться использовать кеш вашего поставщика персистентности (например, в Hibernate кеш второго уровня или кеш запросов) или вашей базы данных.

Также, звоните categoryService.initCategories() в deleteCategory(), вероятно, означает, что вы перегружаете весь список, что не очень хорошо, особенно если у вас много категорий.

Смежные вопросы