I'm modelling a game where multiple players (threads) move at the same time. The information of where a player is located at the moment is stored twice: the player has a variable "hostField" that references to a field on the board and every field has an ArrayList storing the players that are currently located at this field.
I'm not very happy with the fact that I have redundant information, but I found no way avoiding that without looping through a big dataset.
However, when a player moves from one field to another, I'd like to make sure (1) the redundant information stays linked (2) nobody else is manipulating the field at the moment.
Therefore I need to do something like
synchronized(player, field) { // code }
Which is not possible, right?
What should I do? :)
When we use a synchronized block, Java internally uses a monitor, also known as monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object; therefore, all synchronized blocks of the same object can have only one thread executing them at the same time.
Locks In Synchronized Methods When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
In that kind of scenario both threads will be waiting for each other forever to release lock they are already holding thus creating a deadlock. One synchronized method is called from another synchronized method. See example. There are nested synchronized blocks.
synchronized block has better performance as only the critical section is locked but synchronized method has poor performance than block. synchronized block provide granular control over lock but synchronized method lock either on current object represented by this or class level lock.
A trivial solution would be
synchronized(player) { synchronized(field) { // code } }
However, make sure that you always lock the resources in the same order to avoid deadlocks.
Note that in practice, the bottleneck is the field, so a single lock on the field (or on a dedicated, common lock object, as @ripper234 rightly pointed out) may suffice (unless you are concurrently manipulating players in other, conflicting ways).
In fact, synchronization is for code, not objects or data. The object reference used as a parameter in synchronized block represent the lock.
So if you have code like:
class Player { // Same instance shared for all players... Don't show how we get it now. // Use one dimensional board to simplify, doesn't matter here. private List<Player>[] fields = Board.getBoard(); // Current position private int x; public synchronized int getX() { return x; } public void setX(int x) { synchronized(this) { // Same as synchronized method fields[x].remove(this); this.x = x; field[y].add(this); } } }
Then Despite being in the synchronized block the access to field is not protected because the lock is not the same (it being on different instances). So your List of Players for your board can become inconsistent and cause runtime exceptions.
Instead if you write the following code, it will work because we have only one shared lock for all players:
class Player { // Same instance shared for all players... Don't show how we get it now. // Use one dimensional board to simplify, doesn't matter here. private List<Player>[] fields; // Current position private int x; private static Object sharedLock = new Object(); // Any object's instance can be used as a lock. public int getX() { synchronized(sharedLock) { return x; } } public void setX(int x) { synchronized(sharedLock) { // Because of using a single shared lock, // several players can't access fields at the same time // and so can't create inconsistencies on fields. fields[x].remove(this); this.x = x; field[y].add(this); } } }
Be sure to use only a single lock to access all the players or your board's state will be inconsistent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With