Locks are owned per thread, so invoking a synchronized method from within another method synchronized on
the same object will proceed without blocking, releasing the lock only when the outermost synchronized
method returns. This per-thread behavior prevents a thread from blocking on a lock it already has, and permits
recursive method invocations and invocations of inherited methods, which themselves may be synchronized.
The lock is released as soon as the synchronized method terminateswhether normally, with a return
statement or by reaching the end of the method body, or abnormally by throwing an exception. In contrast to
systems in which locks must be explicitly acquired and released, this synchronization scheme makes it
impossible to forget to release a lock.
Synchronization makes the interleaved execution example work: If the code is in a synchronized method, then
when the second thread attempts to access the object while the first thread is using it, the second thread is
blocked until the first one finishes.
For example, if the BankAccount class were written to live in a multithreaded environment it would look
like this:
public class BankAccount {
private long number; // account number
private long balance; // current balance (in cents)
public BankAccount(long initialDeposit) {
balance = initialDeposit;
}
public synchronized long getBalance() {
return balance;
}
public synchronized void deposit(long amount) {
balance += amount;
}
// ... rest of methods ...
}
Now we can explain what is "appropriate" in synchronizing methods.
The constructor does not need to be synchronized because it is executed only when creating an object,
and that can happen in only one thread for any given new object. Constructors, in fact, cannot be declared
synchronized.
The balance field is defended from unsynchronized modification by the synchronized accessor
methods. If the value of a field can change, its value should never be read at the same time another thread is
writing it. If one thread were reading the value while another was setting it, the read might return an invalid
value. Even if the value were valid, a getmodifyset sequence requires that the value not change between being
read and being set, otherwise the set value will be wrong. Access to the field must be synchronized. This
is yet another reason to prefer accessor methods to public or protected fields: Using methods, you can
synchronize access to the data, but you have no way to do so if the fields can be accessed directly outside your
class.
With the synchronized declaration, two or more running threads are guaranteed not to interfere with each
other. Each of the methods will execute in mutual exclusiononce one invocation of a method starts execution,
no other invocations of any of the methods can commence until the original has completed. However, there is
no guarantee as to the order of operations. If the balance is queried about the same time that a deposit occurs,
one of them will complete first but you can't tell which. If you want actions to happen in a guaranteed order,
threads must coordinate their activities in some application-specific way.