For example, an object is like a big house, and the door is always open. There are many rooms in the house (that is, the method ). These rooms are locked (Synchronized Method) and not locked (normal method ). There is a key at the door of the room, which can open all the locked rooms. In addition, I compared all threads that want to call this object method to those who want to enter a room in this house. There are so many things. Let's take a look at how these things work.
Here we will clarify our prerequisites. This object must have at least one Synchronized Method. Otherwise, what is the significance of this key. Of course there will be no such theme.
A person wants to enter a locked room. He comes to the door of the house and sees the key there (meaning no one else wants to use the locked room yet ). So he went up and got the key and used the room as planned. Note that the key will be returned immediately after a locked room is used. Even if he wants to use two locked rooms in a row, he also needs to return the key in the middle and then get it back.
Therefore, in general, the key usage principle is: "pay-as-you-go, pay-as-you-go after use ."
At this time, other people can use unlocked rooms without restriction. One person can use one room, and two people can use one room without restriction. But if someone wants to enter the locked room, he will go to the gate to see it. If you have a key, you can only wait.
If many people are waiting for the key, who will get the key first after the key is returned? Not guaranteed. Like the guy in the previous example who wants to use two locked rooms in a row, if another person is waiting for the key while returning the key, there is no guarantee that this guy can get it again. (Java specifications are not guaranteed in many places, such as thread. how long will the sleep () run be returned after the rest? The thread with the same priority is first executed. When the lock to access the object is released, multiple threads in the waiting pool will get the first priority, and so on. I think the final decision lies in the JVM. The reason for this is that, when JVM makes the above decision, it does not simply make a judgment based on one condition, but based on many items. Too many judgment conditions may affect Java promotion, or it may be because of intellectual property protection. Sun gave me an uncertain message, and it would have been mixed up. It is understandable. But I believe that these uncertainties are not completely uncertain. Because the computer itself runs according to commands. Even if it looks very random, it is actually regular. All those who have learned about computers Know that the names of random numbers in computers are pseudo-random numbers. They are written in certain ways and seem to be random. In addition, it may be because it is too time-consuming and meaningless to confirm the determination. If you are not sure about it, you will not be sure about it .)
Let's take a look at the synchronization code block. It is slightly different from the synchronization method.
1. In terms of size, the synchronization code block is smaller than the synchronization method. You can regard the synchronization code block as a space separated by a locked screen in the unlocked room.
2. The synchronization code block can also be manually specified to obtain the key of another object. It is like specifying which key can be used to open the screen lock, you can use the key of the house; you can also specify the key of another house to open, in this case, you have to go to another house and bring the key, and use the key of the house to open the lock screen of the house.
Remember the key to the other house you got, and it does not affect other people entering the unlocked room of the house.
Why should I use a synchronous code block? I think it should be like this: first, the synchronization part of the program has a great impact on the running efficiency, and a method is usually to create some local variables first and then perform some operations on these variables, such as computing and display. The more Code covered by synchronization, the more serious the impact on efficiency. Therefore, we usually try to narrow down the impact scope. How to do it? Synchronous Code block. We only synchronize the same step in a method, such as an operation.
In addition, the synchronization code block can specify the key. This feature has an additional benefit, that is, it can occupy the key of an object within a certain period of time. Do you still remember the principle of Key Usage in general cases. This is not a common situation. The key you obtained is not never returned, but is returned only when you exit the synchronization code block.
We also used the guy who wanted to lock two rooms in a row as an example. How can I continue to use the other one after I have used up one room. Use the synchronous code block. Create another thread, create a synchronous code block, and point the lock of the code block to the key of the house. Start the thread. As long as you can catch the key of the house when you enter the code block, you can keep it until you exit the code block. That is to say, you can even traverse all locked rooms in the room, or even sleep (10*60*1000), while there are still 1000 threads waiting for this key at the door of the room. Very enjoyable.
Let's talk about the correlation between the sleep () method and the key. When a thread fails to complete synchronization after obtaining the key, if it is forced to sleep (), the key remains there. The key will not be returned until it runs again and completes all synchronization content. Remember, the guy just got tired of his work and went to bed. He didn't finish what he was going to do. In order to prevent others from entering the room and making a mess inside, even when he is sleeping, he should put the only key on his body.
Finally, some may ask, why do we need a key instead of a key? I think this is purely a matter of complexity. One key and one door are safer, but there are many problems involved. Key generation, storage, acquisition, and return. Its complexity may increase with the increase of Synchronization Methods in Geometric Order, seriously affecting efficiency. This is a trade-off. To increase security, the efficiency is greatly reduced.
1. the synchronized keyword has two scopes:
1) In an object instance, synchronized amethod () {} can prevent multiple threads from simultaneously accessing the Synchronized Method of the object (if an object has multiple synchronized methods, as long as a thread accesses one of the synchronized methods, other threads cannot simultaneously access any of this object's synchronized methods ). At this time, the synchronized methods of different object instances are irrelevant. That is to say, other threads can access the Synchronized Method in another object instance of the same class at the same time;
2) is the scope of a class. Synchronized static astaticmethod {} prevents multiple threads from simultaneously accessing the synchronized static method in this class. It can work on all object instances of the class.
2. In addition to using the synchronized keyword before the method, the synchronized keyword can also be used in a block in the method, indicating that only the resources in this block are mutually exclusive. Usage: synchronized (this) {/* block */}. Its scope is the current object;
3. the synchronized keyword cannot be inherited. That is to say, the method of the base class synchronized F () {} is not automatically synchronized F () {} in the inheritance class (){}, instead, it becomes F (){}. You need to explicitly specify a method of the inherited class as the synchronized method;
A simple example of synchronized
Public class textthread
{
/**
* @ Param ARGs
*/
Public static void main (string [] ARGs)
{
// Todo automatically generates method stubs
Txtthread TT = new txtthread ();
New thread (TT). Start ();
New thread (TT). Start ();
New thread (TT). Start ();
New thread (TT). Start ();
}
}
Class txtthread implements runnable
{
Int num = 100;
String STR = new string ();
Public void run ()
{
While (true)
{
Synchronized (STR)
{
If (Num> 0)
{
Try
{
Thread. Sleep (10 );
}
Catch (exception E)
{
E. getmessage ();
}
System. Out. println (thread. currentthread (). getname () + "this is" + num --);
}
}
}
}
}
In the above example, thread. Sleep (10) is used to create a time difference, that is, the chance of an error)
Java's multi-thread support and synchronization mechanism are favored by everyone. It seems that using the synchronized keyword can easily solve the problem of multi-thread shared data synchronization. What exactly? -You must have an in-depth understanding of the role of the synchronized keyword.
In general, the synchronized keyword can be used as the modifier of the function or as the statement in the function, that is, the synchronization method and synchronization statement block. If further classification is performed, synchronized can act on instance variables, object reference, static functions, and class literals (literal constants of class names.
Before proceeding, we need to clarify the following points:
A. no matter whether the synchronized keyword is added to the method or object, the lock it acquires is an object, instead of using a piece of code or function as a lock-and the synchronization method is likely to be accessed by objects in other threads.
B. Each object has only one lock associated with it.
C. Implementing synchronization requires a large amount of system overhead as a cost, and may even cause deadlocks. Avoid unnecessary synchronization control as much as possible.
Next we will discuss the impact of synchronized on code in different places:
Assume that P1 and P2 are different objects of the same class. This class defines synchronization blocks or Synchronization Methods in the following situations, and P1 and P2 can call them.
1. When synchronized is used as a function modifier, the sample code is as follows:
Public synchronized void methodaaa ()
{
//....
}
This is the synchronization method. Which object is synchronized locked at this time? The lock is to call this synchronization method object. That is to say, when an object P1 executes this synchronization method in different threads, they are mutually exclusive to achieve synchronization. However, the other object P2 generated by the class to which this object belongs can call the method with the synchronized keyword.
The above sample code is equivalent to the following code:
Public void methodaaa ()
{
Synchronized (this) // (1)
{
//.....
}
}
(1) What does this mean? It refers to the object that calls this method, such as P1. It can be seen that the synchronization method essentially acts on the object reference. -- The thread that obtains the P1 object lock can call the synchronization method of P1. For P2, the P1 lock has nothing to do with it, in this case, the program may also get rid of the control of the synchronization mechanism, resulting in data confusion :(
2. Synchronization block. The sample code is as follows:
Public void method3 (someobject so)
{
Synchronized (SO)
{
//.....
}
}
In this case, the lock is the so object. Whoever gets the lock can run the code it controls. When a specific object is used as the lock, you can write the program in this way, but when there is no clear object as the lock, just want to synchronize a piece of code, you can create a special instance variable (which must be an object) to act as a lock:
Class Foo implements runnable
{
Private byte [] Lock = new byte [0]; // special instance variable
Public void methoda ()
{
Synchronized (LOCK ){//... }
}
//.....
}
Note: creating a zero-Length byte array object is more economical than any other object-view the compiled bytecode: only three operation codes are required for generating a zero-Length byte [] object, object lock = new object () requires seven lines of operation code.
3. apply synchronized to the static function. The sample code is as follows:
Class foo
{
Public synchronized static void methodaaa () // synchronized static function
{
//....
}
Public void methodbbb ()
{
Synchronized (FOO. Class) // class literal (Class Name literal constant)
}
}
The methodbbb () method in the Code uses class literal as the lock. It produces the same effect as the synchronized static function, and the obtained lock is very special, is the class of the object currently calling this method (class, instead of a specific object generated by this class ).
I remember that I saw in objective Java that using Foo. Class and p1.getclass () for synchronization locks is not the same. p1.getclass () cannot be used to lock this class. P1 refers to the object generated by the foo class.
It can be inferred that if a class defines a static function a of synchronized, it also defines the instance function B of synchronized, when the same object OBJ of this class accesses Methods A and B in multiple threads, the synchronization is not formed because their locks are different. The lock of method A is the object OBJ, and the lock of Method B is the class to which OBJ belongs.
Summary:
Figuring out which object synchronized is locked can help us design safer multi-threaded programs.
There are also some tips to make our synchronized access to shared resources more secure:
1. Define the private instance variable + its get method, instead of the public/protected instance variable. If a variable is defined as public, the object can directly obtain it and change it by bypassing the control of the synchronization method. This is also one of the standard implementations of JavaBean.
2. if the instance variable is an object, such as an array or an arraylist, the above method is still insecure, because after the External Object obtains the reference of this instance object through the get method, and direct it to another object, so this private variable also changes, it is not very dangerous. At this time, you need to add the get method with synchronized synchronization, and only return the clone () of this private object-in this way, the caller obtains the reference of the object copy.