Taming Java Threads (3)

zhaozj2021-02-17  60

Take it back!

Avoid synchronization

Most of the displayed synchronization can be avoided. The method of generally not operating the object status information (e.g., data members) does not need to synchronize, for example: some methods only access local variables (that is, variables within the method within the method), not the class level data member, and these methods External objects are not modified by incoming reference parameters. Methods that meet these conditions do not need to use Synchronization's weight-level operation. In addition, some design modes (Design Pattern) can also be used to avoid synchronization (I will mention later).

You can even avoid synchronization through proper organization of your code. An important concept relative to synchronization is atomic. An atomic operation cannot be interrupted by other threads, and the usual atomic operation is not needed.

Java defines some atomic operations. The generally payment of the variable payment is atom, except for long and double. Look at the following code:

Class unreliable {private long x;

Public long get_x () {returnix;}

Public void set_x (long value) {x = value;}}

Thread 1 call:

Obj.set_x (0);

Thread 2 call:

Obj.set_x (0x123456789Abcdef)

The question is below the following line:

x = value;

JVM for efficiency, did not use X as a 64-bit long integer number, but divided into two 32-bits, respectively pay the value:

X.High_word = value.high_word;

X.LOW_WORD = Value.low_word;

Therefore, there is a thread to switch out by another thread, and the value of its high or low position is changed. Therefore, the value of X can eventually be 0x0123456789abcdef, 0x01234567000000, 0x00000000AbcDef and 0x00000000000000. You can't determine its values, the only solution is to add this keyword to the set_x () and get_x () methods or encapsulate this payment operation in a code segment that ensures atomicity.

So, when the LONG type data is operated, don't just want to be of course. Forced yourself to remember it: Only the direct payment operation is atomic (except for the above example). Others, any expression, like x = Y, X = Y is unsafe, regardless of whether the data type of X or Y is less than 64 bits. It is likely to be premedited by other threads before it is increased before paying the value.

Competitive conditions

In terms, for the multi-threaded problem I mentioned earlier - two threads synchronously operate the same object, making this object's ultimate state - called competitive conditions. Competitive conditions can be used by programmers to ensure that atomic operations, and forget to use Synchronized places. In this sense, Synchronized can be regarded as a tool that guarantees complex, orderable operation, such as paying a Boolean value variable, is an implicit synchronous operation.

Invariate

A effective language level avoiding synchronization is the immutability. An object that cannot be changed from the moment that is not allowed to be changed, such as a String object. But pay attention to this expression: string1 = string2; essentially equivalent String1 = String1 String2; in fact, the third String object containing String1 and String2 is implicit, finally, pointing string1 reference points to the third String. Such an operation is not atom. Since the value of the constant object cannot be changed, it is possible to simultaneously operate multiple threads, and SYNCHRONIZED can be required.

Declaring all data members of a class to FINAL to create a constant type. Those data that are declared for Final is not necessarily written during the statement, but must be fully initialized in the constructor of the class. E.g:

Class i_am_immutable {private final int max_value = 10; private final int blank_final

Public i_am_immutable (int_initial_value) {blank_final = initial_value;}}

A Final type variable that is initialized by the constructor is called Blank Final. Generally, if you frequently read an object, declare it into a constant object is a good way to ensure synchronization, and you can improve the efficiency of JVM, because HotSpot will put it in the stack for use.

Synchronization Packaging (Synchronization Wrappers)

Synchronization or disagreement is the problem. Let us jump out such a thinking mode, the world has no absolute. Is there any way to switch your class flexible to switch between synchronization and not synchronization? There is a very good ready-made example, which is newly introduced to the Java Collection framework, which is used to replace the original, heavy vector, etc. . Any method of the vector is synchronized, this is why it is heavy. For Collections objects, when you need to ensure synchronization, it is generally guaranteed to be synchronized, so there is no need to lock twice (once is the object that contains the method of using the Collection object, once is a lock Collection object itself). Java's solution is to use synchronous packages. The basic principle is from the Decorator mode of the gang-of-four, and a Decorator itself implements an interface, but also includes data members that implement the same interface, but when the external class method calls the same method of internal members. , Control or modify the incoming variable. All classes in this package are Decorator: A BufferedInputStream is only true all methods of virtual category InputStream, but also a member variable pointed to by an InputStream reference. The programmer calls the external container class, which is actually a way to modify the internal object.

We can use this design pattern. To achieve a flexible synchronization method. Such examples:

Interface Some_INTERFACE {Object Message ();

Class not_thread_safe imports Some_interface {public object message () {// implementation of this method, provincial ~~~~~~~~~~~ Return null;}}

class Thread_safe_wrapper implements Some_interface {Some_interface not_thread_safe; public Thread_safe_wrapper (Some_interface not_thread_safe) {this.not_thread_safe = not_thread_safe;}

Public Some_INTERFACE EXTRACT () {return not_thread_safe;

Public synchronized object message () {return not_thread_safe.Message ();}}

When there is no thread security, you can use the not_thread_safe object directly. When you need to consider thread security, you only need to pack it:

Some_Interface object = new not_thread_safe ();

...............

Object = new thread_safe_wrapper (object); // Object now turns a thread safe

When you don't need to consider thread security, you can restore the object object:

Object = ((Thread_safe_wrapper) Object .extract ();

Next, we have to go deep into the underlying mechanism. Ha ha! Don't boring everyone! See you next time!

转载请注明原文地址:https://www.9cbs.com/read-29313.html

New Post(0)