From: http://blog.csdn.net/ilibaba/archive/2009/06/01/4234248.aspx
No. 48 synchronous access to shared variable data
Synchronization not only prevents a thread from seeing objects in an inconsistent state, but also ensures a series of state transition sequences through a series of seemingly sequential executions, objects change from one consistent state to another consistent state.
The synchronized keyword ensures that at the same time, only one thread is executing a statement or a code block. The Java language ensures that reading or writing a variable is atomic unless the variable type is long or double.
The memory model of Java determines that it is necessary to read and write atomic data for reliable communication between threads and mutex access. Let's look at a terrible example:
- // Broken-require synchronization!
- Private Static int nextserialnumber = 0;
- Public static int generateserialnumber (){
- Return nextserialnumber ++;
- }
To improve it, you only need to add the synchronized modifier in the generateserialnumber () statement.
To terminate a thread, we recommend that the thread poll a domain. If the value of this field changes, it indicates that the thread should terminate itself. The following example shows how to synchronize data.
- // Broken-requires synchronization
- Public class stoppablethread extends thread {
- Private Boolean stoprequested = false;
- Public void run (){
- Boolean done = false;
- While (! Stoprequested &&! Done ){
- ... // Do what needs to be done in the thread
- }
- }
- Public void requeststop (){
- Stoprequested = true;
- }
- }
The improvements are as follows:
- // Properly synchronized cooperative thread temination
- Public class stoppablethread extends thread {
- Private Boolean stoprequested = false;
- Public void run (){
- Boolean done = false;
- While (! Stoprequested ()&&! Done ){
- ... // Do what needs to be done in the thread
- }
- }
- PublicSynchronizedVoid requeststop (){
- Stoprequested = true;
- }
- PrivateSynchronizedBoolean stoprequested (){
- Return stoprequested;
- }
- }
Another improvement is that when stoprequested is declared as volatile, synchronization can be omitted.
About singleton:
Let's take a look at the lazy initialization issue,The dual access mode may not always work normally unless the shared variable contains a primitive value.. Example:
- // The double-check idion fro lazy initialization-broken!
- Private Static Foo = NULL;
- Public static Foo getfoo (){
- If (FOO = NULL ){
- Synchronized (FOO. Class ){
- If (FOO = NULL) Foo = new Foo ();
- }
- }
- Return Foo;
- }
The easiest modification is to save the trouble of initialization:
- // Normal static initialization (not lazy)
- Private Static finall Foo = new Foo ();
- Public static Foo getfoo (){
- Return Foo;
- }
Or use the correct synchronization method, but it may increase the synchronization Overhead:
- // Properly synchronized lazy Initialization
- Private Static Foo = NULL;
- Public static synchronized Foo getfoo (){
- If (FOO = NULL) Foo = new Foo ();
- Return Foo;
- }
The On-Demand container initialization mode is also good, but it can only be used for static domains, not instance domains.
- // The initialize-on-demand holder class Idiom
- Private Static class fooholder (){
- Static final Foo = new Foo ();
- }
- Public static Foo getfoo () {return fooholder. Foo ;}
In short, whenever multiple threads share variable data, each thread that reads or writes data must obtain a lock. If there is no synchronization, the modifications made by one thread cannot be observed by another thread.
No. 49 avoid excessive Synchronization
Usually, do as little work as possible in the synchronization area. To avoid deadlocks.
A large amount of synchronization may cause performance loss.
Whether a class should be thread-safe or thread-compatible. If the class is used in a synchronous or non-synchronous environment, A reasonable method is to provide two versions at the same time. There are the following guiding principles:
1) One approach is to provide a packaging class to implement interfaces. Colleagues can perform proper synchronization operations before forwarding method calls to corresponding methods in internal objects.
2) the second approach is applicable to classes that are not designed for extension or re-implementation. It provides an unsynchronized class and a subclass. The subclass contains only some synchronized methods, which are called to the corresponding methods in the superclass in turn.
If a class or a static method depends on a variable static field, it must be synchronized internally, even if it is only used by a single thread. In this case, it is impossible for customers to execute external synchronization, because it is impossible for other customers to execute external synchronization.
In short, in order to avoid deadlocks and data damage, do not call external methods from within the synchronization area. Colleague: restrict the workload within the synchronization area.
No. 50 never call wait outside the loop
Standard mode of wait:
Synchronized (OBJ ){
While (<condition does not hold>)
OBJ. Wait ();
... // Perform action appropriate to Condition
}
Wait is always used to call the wait method through a wait loop, and wait is never called outside. Test conditions before waiting. If the conditions are true, you can skip waiting. If condition + wait before notify has been called, the thread will always wake up from the waiting state. Testing after waiting is necessary to ensure security. When the conditions are not met, there are some reasons to wake up a thread: 1) another thread may get a lock between calling y and waiting for the thread to wake up, the thread that gets the lock has changed the protected State; 2) the condition is not true, and some threads accidentally call notify; 3) when the notification thread is awake, policyall is used; 4) false wakeup, though rarely possible.
No. 51 should not depend on the thread Scheduler
The correctness of applications cannot depend on the thread scheduler. Otherwise, the resulting application is neither robust nor portable. As an inference, do not rely on thread. Yield or thread priority. These facilities only affect the schedulers. They can be used to improve the service quality of a system that can work normally,But it should never be used to "correct" a program that could not work.
The best way to write robust, responsive, and portable multi-threaded applications is to make sure that there are only a few runnable threads at any given moment. The main technique used in this method is to let each thread do a small amount of work, then use object. Wait to wait for a condition to occur, or use thread. sleep for a period of time.
Document-based thread security
Each class should clearly describe its thread security attributes in the document. The synchronized modifier appears in the declaration of a method, which is an implementation detail and is not part of the exported API documentation.
To be safely used by multiple threads, a class must clearly describe the thread security level it supports in the document.
1)Immutable-instances of this class remain unchanged for other customers and do not require external synchronization.See 13.
2) thread-safe (thread-safe)-the instance of this class is variable, but all the places contain sufficient synchronization means, these instances can be used concurrently without external synchronization.
3) conditional thread-safe-This class (or associated class) contains some methods that must be called sequentially, it cannot be disturbed by other threads. In addition, the thread security level is the same as that in the previous scenario.To eliminate the possibility of interference by other threads, the customer must obtain an appropriate lock during the execution of this method sequence.. Such as hashtable or vector,Their iterators require external synchronization. For example:
- Hashtable H = ...;
- Synchronized (h ){
- For (enumeration E = H. Keys (); E. hasmoreelements ();)
- F (E. nextelement ());
- }
4) thread-compatible (thread-compatible)-external synchronization is used on the periphery of each method call. In this case, instances of this class can be used safely and concurrently. For example, arraylist or hashmap
5) The thread-hostile class cannot be safely used by multiple threads concurrently, even if all method calls are surrounded by external synchronization. Generally, the root of the opposition between threads is that static data needs to be modified in this method, which may affect other threads.
For Conditional thread security classes, specify in the document "which object should be locked in order to allow the method call sequence to be executed in an atomic way ".
No. 53 avoid using thread groups
In addition to threads, locks, and monitors, the thread System also provides a basic abstraction, namely thread-group ). However, thread groups do not provide many useful functions.
One exception is that when a thread in the thread group throws an uncaptured exception, the threadgroup. uncaughtexception method is automatically called. The execution environment uses this method to respond to uncaptured exceptions in an appropriate manner.
No. 54 write the readobject method in a protective manner
Writing a readobject method of a class is equivalent to writing a public constructor. No matter what kind of byte stream is passed to it, it must generate a valid instance. The following are the guidelines for the robust readobject method:
① For classes whose object reference fields must be kept private, a protective copy of "objects to be saved in these fields" is performed. The variable components of the non-variable class belong to this category.
② For classes with constraints, check whether the constraints are met. If not, an invalidobjectexception exception is thrown. These checks should follow all protective copies.
③ If the entire object graph must be valid after the object graph is deserialized, use the objectinputvalidation interface.
④ Do not call methods that can be rewritten in the class either directly or indirectly.
⑤ The readresolve method may be used to replace the protective readobject method.
Strictly speaking, readobject is a constructor that uses throttling as a unique parameter. When facing a manually forged byte stream, the object generated by readobject violates the constraints of the class to which it belongs. The initial method is to perform a binding check on the readobject method, as shown in the following example:
- Private void readobject (objectinputstream s) throws ioexception, classnotfoundexception {
- S. defaultreadobject ();
- // Check that our invariants are satisfied
- If (start. compareto (end)> 0) throw new invalidobjectexception (start + "after" + end );
- }
The above prevention measures can still be attacked: forge a byte stream, which starts with the byte stream generated by a valid period instance, and then attaches two additional references, points to two internal private date domains in the period instance. Attackers can exploit this vulnerability to attack the internal domain. Therefore, when an object is deserialized, a reference to an object that the customer should not own must be protected if the domain contains such an object reference, this is very important. For example:
- Private void readobject (objectinputstream s) throws ioexception, classnotfoundexception {
- S. defaultreadobject ();
- Start = new date (start. gettime ());
- End = new date (end. gettime ());
- If (start. compareto (end)> 0) throw new invlaidobjectexception (start + "after" + end );
- }
No. 57 provide a readresolve method when necessary
Whether it's Singleton or another instance-controlled class, you must use the readresolve method to protect "instance-controlled constraints ". Essentially, the readresovle method converts a readobject method from a real public constructor to a real public static factory. For classes that prohibit non-package inheritance, the readresolve method is also very useful as an alternative to the protective readobject method.
The following sigleton class:
- Public class Elvis {
- Public static final Elvis instance = new ELVIS ();
- Private ELVIS (){
- ...
- }
- ... // Remainder omitted
- }
If Elvis instance serializes an interface, the following readresolve method is sufficient to ensure its Singleton attribute.
- Private object readresolve () throws objectstreamexception {
- // Return the one true Elvis and let the GC take care of the Elvis impersonator
- Return instance;
- }
Not only are Singleton objects necessary, but the readresolve method is also required for all other instance controlled classes (such as type security enumeration types.
The second usage of the readresolve method is to act as a conservative alternative to the protective readobject method as recommended in article 56th. In this case, the readobject method in Article 1 can be replaced by the following example:
- // The defensive readresolve Idiom
- Private object readresolve () throws objectstreamexception (){
- Return New Period (START, end );
- }
For classes that can be inherited, The readresolve method may not be able to replace the protective readobject method. If the readresolve method of the superclass is final, the subclass instance cannot be deserialized normally. If the readresolve method of the superclass is rewritable, the malicious subclass may use a method to rewrite it. This method returns a damaged instance.
Conclusion: It took several months to finish reading this book intermittently. During this period, I made several projects and was busy for a while. The reading progress was somewhat delayed, now I have forgotten all the notes I have prepared. But it doesn't matter. I can go back and see it later. Let's learn something new...
------
I changed the typos and added several missing rules.
Feeling, the graphic XXX series always gave me a long-winded feeling. After reading it, I thought it was not very helpful. It may not be very good to combine it with practical problems. A lot of words always made me feel heavy. I am very grateful to some enthusiastic readers for taking notes, although Reading Notes makes me feel hard to digest. May be waiting for an opportunity to let me understand the true meaning of the book. Unfortunately, in such a fast food and cruel society, no one will allow you to spend time prepare yourself.
It took two or three days to read the notes and a part of the book, and it seems that the current valuable review time is wasted. However, I do not know whether it is futile to review. The contempt of so many companies and the compare of people around me have really put me into a depression.