Rule 3. synchronized: 只影响该类, 不影响子类或不受父类影响 (Synchronization requirements are a part of the implementation of a class.)
Rule 4. synchronized: 类对象和实例对象互不影响(Acquiring the Class object lock in a static synchronized method has no effect on any objects of that class.)
Rule 5. synchronized: 外围类实例和内嵌类实例互不影响(Another common use of the synchronized statement is for an inner object to synchronize on its enclosing object)
Like any other object, an inner object is independently synchronized. acquiring the lock of an inner object has no effect on its enclosing object's lock, nor does acquiring the lock of an enclosing object affect any enclosed inner objects. An inner class that needs to synchronize with its enclosing object must do so explicitly and a synchronized statement is a perfect toolthe alternative is to declare a synchronized method in the enclosing class just for the inner class to use.
assert Thread.holdsLock(this);Conclusion 1. Don't Use synchronized(obj.getClass())
Conclusion 2. Client-side synchronization
An object can have its lock acquired, which prevents any of its synchronized methods from being invoked except by the lock holder performing the series of invocations. Similarly, you can acquire the locks of each of the objects involved and then invoke the series of methods on those objects but watch out for deadlock (see Section 14.7 on page 362). As long as the object's methods are already synchronized on the current object's lock, then other clients of the object need not use client-side synchronization.
14.4. wait, notifyAll, and notifyThe wait and notification methods are defined in class Object and are inherited by all classes. They apply to particular objects, just as locks do. There is a standard pattern that is important to use with wait and notification. The thread waiting for a condition should always do something like this: synchronized void doWhenCondition() { A number of things are going on here:
Using notifyAll wakes up all waiting threads, whereas notify picks only one thread to wake up. Multiple threads may be waiting on the same object, possibly for different conditions. If they are waiting for different conditions, you should always use notifyAll to wake up all waiting threads instead of using notify. Otherwise, you may wake up a thread that is waiting for a different condition from the one you satisfied. That thread will discover that its condition has not been satisfied and go back to waiting, while some thread waiting on the condition you did satisfy will never get awakened. Using notify is an optimization that can be applied only when:
Otherwise you must use notifyAll. If a subclass violates either of the first two conditions, code in the superclass that uses notify may well be broken. To that end it is important that waiting and notification strategies, which include identifying the reference used (this or some other field), are documented for use by extended classes. In a multithreaded system you very rarely want to busy-wait. You should always suspend until told that what you are waiting for may have happened. This is the essence of thread communication with the wait and notifyAll/notify mechanism. |
14.5. Details of Waiting and Notification
You can invoke these methods only from within synchronized code, using the lock for the object on which they are invoked. The invocation can be directly made from the synchronized code, or can be made indirectly from a method invoked in such code. You will get an IllegalMonitorStateException if you attempt to invoke these methods on an object when you don't hold its lock. 细节 1. Only notifications that occur after the wait commences will affect a waiting thread. If no threads are waiting when either notifyAll or notify is invoked, the notification is not remembered. If a thread subsequently decides to wait, an earlier notification will have no effect on it. 细节 2. wait(long timeout)未必会导致 wait 在有限时间内返回 The use of a time-out is a defensive programming measure that allows you to recover when some condition should have been met but for some reason (probably a failure in another thread) has not. Because the lock of the object must be reacquired, the use of a time-out cannot guarantee that wait will return in a finite amount of time. 细节 3. wait始 终在循环中的另一个原因 It is also possible that some virtual machine implementations will allow so-called "spurious wakeups" to occurwhen a thread returns from wait without being the recipient of a notification, interruption, or time-out. This is another reason that wait should always be performed in a loop that tests the condition being waited on. |
There is a second synchronization mechanism that doesn't provide the exclusive access of monitors, but that again ensures that each read of a variable returns the most recently written valuethe use of volatile variables. Fields (but not array elements) can be declared with the volatile modifier. A write to a volatile variable synchronizes with all subsequent reads of that variable. If currentValue was declared as volatile then the example code we showed would be correctly synchronized and the latest value would always be displayed. The use of volatile variables is seldom a replacement for the use of synchronized methods or statements on its own, because they don't provide atomicity across different actions. Rather, volatile variables are most often used for simple flags to indicate something has occurred, or for writing lock-free algorithms that incorporate use of the atomic variables mentioned in Section 25.9.
Rule 4. volatile 另外一个副作用就是让long或double类型的变量读写也变成原子操作几个最佳实践: A few other synchronization actions help make multithreading work nicely:
Starting a thread synchronizes with the first action performed by that thread when it executes. This ensures that a newly started thread sees any data that was initialized by the creating threadincluding the thread's own fields.
The final action of a thread synchronizes with any action that detects that the thread has terminatedsuch as calling isAlive or invoking join on that thread. This ensures, for example, that if you join a thread you can see all data written by that thread before it terminatedsuch as the results of its computation.
Interrupting a thread synchronizes with any other action that determines that the thread has been interrupted, such as the thread throwing InterruptedException or another thread invoking isInterrupted on the thread.
The write of the default value (zero, null, or false) to any field synchronizes with the first action in any thread. This ensures that even in incorrectly synchronized programs a thread will never see arbitrary values in fieldseither a specific value written by some thread will be seen or the default value of the field will be seen.