Что именно делает синхронизированный? Заблокировать функцию или заблокировать функцию объектов?

Мне интересно, как именно «синхронизировано» работает в java.

Допустим, я моделирую настольную игру, состоящую из нескольких полей. Я реализую поля как класс (Field) и доску как класс (Board), который содержит ряд полей. Скажем далее, я смоделировал метод moveTo(Player pl) в поле, чтобы игрок мог перейти на это поле. Каждый игрок представлен нитью.

Хотя все потоки должны выполнять некоторые действия одновременно (например, бросать кубики), в каждый момент времени должен двигаться только один игрок.

Как я могу это гарантировать? Достаточно ли синхронизировать метод moveTo(Player pl)? Или мне нужен каскадный метод в Board, чтобы убедиться, что только один игрок движется одновременно? (Или есть лучшее решение)?

Подводя итог:
будет ли "синхронизированный" блокировать метод в КАЖДОМ объекте, который имеет этот метод, или синхронизированный заблокирует метод только в объекте, который используется в данный момент?
И если второй является case: есть ли простой способ заблокировать метод для каждого объекта, в котором реализован этот метод?

Спасибо!!!


person speendo    schedule 03.01.2011    source источник
comment
synchronized никогда не блокирует функцию, и точка. Вы можете всегда блокировать только объект. С методом экземпляра это this. В случае статического метода это объект класса, в котором определен метод (MyClass.class).   -  person Mark Peters    schedule 03.01.2011
comment
только потому, что вы спросили, зачем мне многопоточность: на самом деле я реализую какую-то многопользовательскую игру pacman в качестве домашнего задания. Каждый игрок и каждый призрак должен быть нитью. Однако мне нужно проверять, попадает ли игрок в призрака или наоборот после каждого шага. В этот момент я иногда получаю исключения, говорящие мне что-то вроде Ghost-A, хотел удалить Player-B из поля-XY, но Player-B там больше не было. Я думаю, что эта ошибка возникает из-за того, что перемещение потоков не было синхронизировано.   -  person speendo    schedule 03.01.2011
comment
Синхронизация была бы одним из решений этой проблемы. Но не единственный.   -  person Falmarri    schedule 03.01.2011


Ответы (4)


Я думаю, вы хотели бы следующее:

class Field {

    // instance of the board
    private Board board; 

    public void moveTo(Player p){ 
        synchronized (board) {
            // move code goes here
        }
    }
}

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

Если бы вы просто написали:

public synchronized void moveTo(Player p){ 

вы бы только заверили, что игроки не могут одновременно перемещаться на одно и то же поле. Это связано с тем, что когда метод написан с синхронизацией в определении, он будет заблокирован на уровне объекта. Таким образом, каждый экземпляр Field будет своим собственным объектом блокировки, и, таким образом, игроки могут перемещаться одновременно, если они не перемещаются в одно и то же поле.

person jjnguy    schedule 03.01.2011
comment
Очень хорошее эмпирическое правило: не синхронизировать/блокировать объекты, не являющиеся конечными! - person Voo; 12.01.2014

синхронизированный блокирует объект, а не метод. В Java нет функций.

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

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

person Peter Lawrey    schedule 03.01.2011
comment
Синхронизация объекта класса может иметь некоторые непреднамеренные проблемы, если есть также синхронизированные статические методы. Если вы пытаетесь синхронизировать один конкретный критический раздел, создайте и синхронизируйте объект блокировки специально для него, например private static final Object methodAMutex = new Object(). Или используйте примитивы параллелизма, добавленные в версии 6. - person Mark Peters; 03.01.2011
comment
Конечно - было бы глупо блокировать функцию в объектно-ориентированном языке... Спасибо, я не подумал об этом раньше! - person speendo; 03.01.2011
comment
@ Марсель: Хорошо. Это зависит. В python вы можете блокировать функции, но это следствие того, что функции являются объектами. - person Falmarri; 03.01.2011

Синхронизация блокирует доступ к ресурсу. Этот ресурс может быть либо функцией, либо объектом (включая объект this).

Мы не можем дать вам конкретный совет без конкретного примера.

В вашем примере, если игроки могут делать только 1 ход за раз, зачем им быть в своих тредах? Зачем им нужно бросать кости одновременно?

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

And if the second is the case: is there an easy way to lock a function for every object that has this function implemented?

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

person Falmarri    schedule 03.01.2011

Это зависит от того, где он используется.

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

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

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

Как только вы покидаете область синхронизированного блока, вы отказываетесь от монопольного удержания блокировки.

person Edwin Buck    schedule 03.01.2011
comment
отличная аватарка, кстати - это из игры лайф? - person speendo; 03.01.2011