Magic Feather example.
Each object has a magic feather called a monitor.
When you use the synchronized
keyword on a method,
you're gaining the monitor of the current object or locking
it. As long as a thread possesses the monitor or lock of an
object no other thread can get the lock for that object. (Another
thread may be able to lock a different object in the same class,
however.)
When you use the synchronized
modifier to specify
that a method is synchronized, you are locking on the particular
object whose method is invoked. (Static methods can also be
synchronized. In this case, the lock is placed on the
java.lang.Class
object associated with the object's class.)
Since there's only one lock per object, it's not just the
synchronized method that can't be invoked by other threads. It's
any other synchronized method or block of code in that object.
You can synchronize at a lower level than a method. For example
the following program had problems if another thread changed the
value of count
or this.count
while the assignment
was taking place.
public class Counter {
private int count = 0;
public void count() {
int localCopy = this.count;
int limit = localCopy + 100;
while (localCopy++ != limit) System.out.println(localCopy);
this.count = localCopy;
}
}
You can fix this by synchronizing the lines of code that refer to the field:
public void count() {
int localCopy;
synchronized (this) {
localCopy = this.count;
}
int limit = localCopy + 100;
while (localCopy++ != limit) System.out.println(localCopy);
synchronized (this) {
this.count = localCopy;
}
}
Note, however, that this "solution" basically prevents the correct
current value of count
from being read while the
count()
method is running. We really need a
getCount()
method to demonstrate this.