Home  >  Article  >  Java  >  Detailed explanation of java synchronized

Detailed explanation of java synchronized

高洛峰
高洛峰Original
2016-12-13 10:55:141288browse

Java language keywords, when used to modify a method or a code block, can ensure that at most one thread executes the code at the same time.

1. When two concurrent threads access the synchronized (this) synchronization code block in the same object object, only one thread can be executed at a time. Another thread must wait for the current thread to finish executing this code block before it can execute this code block.

2. However, when a thread accesses a synchronized (this) synchronized code block of object, another thread can still access the non-synchronized (this) synchronized code block in the object.

3. What is particularly critical is that when a thread accesses a synchronized (this) synchronized code block of object, other threads will be blocked from accessing all other synchronized (this) synchronized code blocks in object.

4. The third example is also applicable to other synchronization code blocks. That is to say, when a thread accesses a synchronized(this) synchronized code block of object, it obtains the object lock of this object. As a result, other threads' access to all synchronized code parts of the object object is temporarily blocked.

5. The above rules are also applicable to other object locks.

Example:
1. When two concurrent threads access the synchronized (this) synchronization code block in the same object object, there can only be one at a time The thread gets executed. Another thread must wait for the current thread to finish executing this code block before it can execute this code block.

package ths;

public class Thread1 implements Runnable {
                                                                            using using using using using         through using       through   through out through out through out out out through out Through out off   ‐ for   ‐ ‐ ‐‐ ‐ ‐ to System.out.println(Thread .currentThread().getName() + " synchronized loop " + i); 1();
         Thread ta = new Thread (t1, "A");
         Thread tb = new Thread(t1, "B"); A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
  B synchronized loop 4

2. However, When a thread accesses a synchronized(this) synchronized code block of an object, another thread can still access the non-synchronized(this) synchronized code block in the object.

package ths;

public class Thread2 {  
     public void m4t1() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }  
     }  
     public void m4t2() {  
          int i = 5;  
          while( i-- > 0) {  
               System.out.println(Thread.currentThread().getName() + " : " + i);  
               try {  
                    Thread.sleep(500);  
               } catch (InterruptedException ie) {  
               }  
          }  
     }  
     public static void main(String[] args) {  
          final Thread2 myt2 = new Thread2();  
          Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );  
          Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t2();   }  }, "t2"  );  
          t1.start();  
          t2.start();  
     } 
}

结果:  
     t1 : 4  
     t2 : 4  
     t1 : 3  
     t2 : 3  
     t1 : 2  
     t2 : 2  
     t1 : 1  
     t2 : 1  
     t1 : 0  
     t2 : 0

     三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

Re // Modify Thread2.m4t2 () Method:

Public void M4T2 () {
Synchronized (this) {
int i = 5;
about (i- & gt; 0) {
System.out.println (Thread. currentThread().getName() + " : " + i);                                                                                   ) {
                                                                                                                                                 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3

t2 : 2

t2 : 1

t2 : 0

4. The third example is also applicable to other synchronizations code block. That is to say, when a thread accesses a synchronized(this) synchronized code block of object, it obtains the object lock of this object. As a result, other threads' access to all synchronized code parts of the object object is temporarily blocked.


                                                                                            Thread2.m4t2                                                                                                                                                                                   , .out.println(Thread.currentThread( ).getName() + " : " + i);
                                                                                       ​} }
}
}

Result:
t1 : 4
t1 : 3
t1 : 2

t1 : 1

t1 : 0

t2 : 4

t2 : 3

t2 : 2

t2 : 1
t 2: 0

5. The above rules also apply to other object locks:

package ths;

public class Thread3 { 
     class Inner { 
          private void m4t1() { 
               int i = 5; 
               while(i-- > 0) { 
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i); 
                    try { 
                         Thread.sleep(500); 
                    } catch(InterruptedException ie) { 
                    } 
               } 
          } 
          private void m4t2() { 
               int i = 5; 
               while(i-- > 0) { 
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); 
                    try { 
                         Thread.sleep(500); 
                    } catch(InterruptedException ie) { 
                    } 
               } 
          } 
     } 
     private void m4t1(Inner inner) { 
          synchronized(inner) { //使用对象锁 
          inner.m4t1(); 
     } 
     private void m4t2(Inner inner) { 
          inner.m4t2(); 
     } 
     public static void main(String[] args) { 
          final Thread3 myt3 = new Thread3(); 
          final Inner inner = myt3.new Inner(); 
          Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1"); 
     Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2"); 
     t1.start(); 
     t2.start(); 
  } 
}

结果:

尽管线程t1获得了对Inner的对象锁,但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。

     t1 : Inner.m4t1()=4  
     t2 : Inner.m4t2()=4  
     t1 : Inner.m4t1()=3  
     t2 : Inner.m4t2()=3  
     t1 : Inner.m4t1()=2  
     t2 : Inner.m4t2()=2  
     t1 : Inner.m4t1()=1  
     t2 : Inner.m4t2()=1  
     t1 : Inner.m4t1()=0  
     t2 : Inner.m4t2()=0

现在在Inner.m4t2()前面加上synchronized:

                                                                                  int i = 5; )= " + i);
                                                                                                                                                                                                                                                                                                 
                                                                                                                                                  Irrelevant part, but because t1 first obtained the object lock on Inner, t2's access to Inner.m4t2() is also blocked, because m4t2() is a synchronized method in Inner.

t1 : Inner.m4t1()=4
t1 : Inner.m4t1()=3
t1 : Inner.m4t1()=2
t1 : Inner.m4t1()=1
t1 : Inner.m4t 1()= 0
t2 : Inner.m4t2()=4

t2 : Inner.m4t2()=3

t2 : Inner.m4t2()=2

t2 : Inner.m4t2()=1

t2 : Inner.m4t2 ()= 0

Second article:

synchronized keyword, which includes two usages: synchronized method and synchronized block.
1. synchronized method: declare the synchronized method by adding the synchronized keyword to the method declaration. For example:
public synchronized void accessVal(int newVal);
The synchronized method controls access to class member variables: each class instance corresponds to a lock, and each synchronized method must obtain the lock of the class instance that calls the method

Execution, otherwise the thread to which it belongs is blocked. Once the method is executed, it will exclusively occupy the lock. The lock will not be released until returning from the method. After that, the blocked thread can obtain the lock and re-enter the executable

state. This mechanism ensures that for each class instance at the same time, at most one of all its member functions declared as synchronized is in the executable state (because at most only one can obtain the lock corresponding to the class instance), thus effectively avoiding Access violation of class member variables (as long as all methods that may access class member variables are declared synchronized)

.

In Java, not only class instances, each class also corresponds to a lock. In this way, we can also declare the static member functions of the class as synchronized to control its access to the static member variables of the class. Defects of the

synchronized method: If a large method is declared as synchronized, it will greatly affect the efficiency. Typically, if the thread class method run() is declared as

synchronized, because it has been running for the entire life cycle of the thread. run, thus causing its calls to any synchronized methods of this class to never succeed. Of course we can solve this problem by putting the code that accesses class member variables into a special method, declaring it synchronized, and calling it in the main method, but Java provides us with a better solution The solution is synchronized blocks.
2. synchronized block: declare synchronized block through synchronized keyword. The syntax is as follows:

synchronized(syncObject) {

//Code that allows access control

}

synchronized block is a code block in which the code must obtain the lock of the object syncObject (as mentioned before, it can be a class instance or class) Before it can be executed, the specific mechanism is the same as mentioned above. Because it can target any code block and specify the locked object arbitrarily, it has high flexibility.

Some understanding of synchronized(this)

1. When two concurrent threads access the synchronized(this) synchronization code block in the same object object, only one thread can be executed at a time. Another thread must wait for the current thread to finish executing this code block before it can execute this code block.

2. However, when a thread accesses a synchronized(this) synchronized code block of object, another thread can still access the non-synchronized


(this) synchronized code block in the object.

Third, what is particularly critical is that when a thread accesses a synchronized(this) synchronization code block of object, other threads access all other synchronized(this) in object

Access to synchronized code blocks will be blocked.
4. The third example is also applicable to other synchronized code blocks. That is to say, when a thread accesses a synchronized(this) synchronized code block of object, it obtains the object lock of this

object. As a result, other threads' access to all synchronized code parts of the object object is temporarily blocked.
5. The above rules also apply to other object locks

http://hi.baidu.com/sunshibing/blog/item/5235b9b731d48ff430add14a.html
Usage of synchronized in java

For example: an object is like a big house , the door is always open. There are many rooms (that is, methods) in the house.

These rooms are either locked (synchronized method) or unlocked (normal method). There is a key at the door of the room. This key can open all locked rooms.

In addition, I compare all threads that want to call the object's methods to people who want to enter a certain room in this house. That’s all there is to it, let’s take a look at how these things work with each other.

Here we first clarify our prerequisites. The object has at least one synchronized method, otherwise this key has no meaning. Of course, there will be no such theme of ours.

A person wanted to enter a locked room. He came to the door of the house and saw the key there (indicating that no one else wanted to use the locked room yet). So he walked up, got the keys

, and used the rooms according to his plan. Note that he returns the key immediately after each use of the locked room. Even if he wants to use two locked rooms in a row, he has to return the key and get it back in the middle.

Therefore, the principle of using keys under normal circumstances is: "Borrow as you use, return as soon as you use it."

At this time, other people can use the unlocked rooms without restrictions, and one person can use one room , two people can use one room, there is no limit. But if someone wants to enter a locked room, he has to run to the door to see it. If you have the key, of course you can take it and leave. If you don't have the key, you can only wait.

If many people are waiting for this key, who will get the key first when the key is returned? Not guaranteed. Like the guy in the previous example who wants to use two locked rooms in a row, if there are other people waiting for the key when he returns the key, there is no guarantee that this guy can get it again. (The JAVA specification clearly states in many places that there are no guarantees. For example, how long will

Thread.sleep() return to running after a break? Which thread with the same priority will be executed first? When the lock to access the object is released, it will be in the waiting pool. Which of the multiple threads will get priority, etc. I think the final decision lies with the JVM. The reason why there is no guarantee is because when the JVM makes the above decision, it does not simply make it based on one condition. The judgment is based on many conditions. If there are too many judgment conditions, it may affect the promotion of JAVA. It may also be due to intellectual property protection reasons and it will be ignored.

. It’s understandable. But I believe that these uncertainties are not completely uncertain, because even the seemingly random phenomena can be found by anyone who has studied computers. As you know, the scientific name for random numbers in computers is pseudo-random numbers, which are written by people using a certain method. They just look random. In addition, it may be because it is too troublesome and meaningless to determine. I’m not sure yet.)

Let’s take a look at the synchronization code block. It is slightly different from the synchronization method.

1. In terms of size, synchronized code blocks are smaller than synchronized methods. You can think of a synchronized code block as a space in an unlocked room separated by a locked screen.

2. The synchronization code block can also manually specify the key of another object. Just like specifying which key can be used to open the lock of this screen, you can use the key of this house; you can also specify

to use the key of another house to open it. In this case, you have to run to another house Get that key there and use that house key to open the locked screen of this house.

                                                                                                                                                                                                                               Remember that the key of the other house that you have obtained will not prevent others from entering the unlocked room of that house.

                                                                                                                          Why use synchronized code blocks? I think it should be like this: First of all, the synchronization part of the program affects the operating efficiency, and a method usually creates some local variables first, and then performs some operations on these variables, such as calculations, display, etc.; and The more code covered by synchronization, the more severe the impact on efficiency. So we usually try to keep its scope of impact as small as possible.

How to do it? Synchronized code blocks. We only synchronize the parts of a method that should be synchronized, such as operations.

码 In addition, synchronous code blocks can specify the characteristics of the key to have an additional benefit, which is the key that can occupy a certain object within a certain period of time. Do you still remember the principles of using keys under normal circumstances? These are no ordinary circumstances. The key you obtain is not returned forever, but is returned when you exit the synchronized code block.连 Use the guy who wants to use two locking rooms in a row for an example. How can I continue to use another room after using one room? Use synchronized code blocks. First create another thread, make a synchronization code block, and point the lock of that code block to the key of the house. Then start that thread. As long as you can grab the key to this house

when you enter that code block, you can keep it until you exit that code block. In other words, you can even traverse all the locked rooms in this room, and even sleep (10*60*1000), but there are still

1000 threads waiting for the key at the door. It's quite enjoyable. P Let's talk about the correlation between the Sleep () method and the key. If a thread is forced to sleep() after getting the key and has not completed the synchronization content, the key will still be there. The key will not be returned until it is run again and all synchronization content is completed. Remember, the guy just got tired from working and went to take a rest. He didn't finish what he wanted to do. In order to prevent others from entering the room and making a mess inside, he had to wear the only key even when sleeping.

Finally, some people may ask, why do we need one key to open the door instead of one key for each door? I think this is purely a matter of complexity. One key for one door is certainly more secure, but it will involve a lot of problems. The generation, storage, acquisition, return of keys, etc. Its complexity may increase geometrically as the number of synchronization methods increases, seriously affecting efficiency. This can be regarded as a matter of trade-off. How undesirable it is to greatly reduce efficiency in order to increase a little bit of security.

A simple example of synchronized

public class TextThread {

public static void main(String[] args) {

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() {

synchronized (str) {

while (num > 0) {

try {
Thread.sleep(1);
} catch (Exception e) {
e .getMessage();
}
System.out.println(Thread.currentThread().getName()
+ "this is " + num--);
}

}

}
}

In the above example, To create a time difference, which is the opportunity for errors, Thread.sleep(10) is used


Java's multi-thread support and synchronization mechanism are loved by everyone. It seems that using the synchronized keyword can easily solve multi-threading Shared data synchronization problem. What is it like

? ——It is necessary to have an in-depth understanding of the role of the synchronized keyword before we can make a conclusion.


In general, the synchronized keyword can be used as a modifier of a function, or as a statement within a function, which is what we usually call synchronization methods and synchronization statement blocks. If classified further,

synchronized can act on instance variables, object references, static functions and class literals (class name literals).

Before further elaboration, we need to clarify a few points:

A. Regardless of whether the synchronized keyword is added to a method or an object, the lock it acquires is an object, rather than treating a piece of code or a function as a lock - and the synchronized method is likely to be accessed by objects in other threads.

B. Each object has only one lock associated with it.

C. Achieving synchronization requires a lot of system overhead and may even cause deadlock, so try to avoid unnecessary synchronization control.

Next, let’s discuss the impact of synchronized in different places on the code:

Assume that P1 and P2 are different objects of the same class. This class defines synchronization blocks or synchronization methods in the following situations. P1 and P2 are They can all be called.

1. When using synchronized as a function modifier, the sample code is as follows:

Public synchronized void methodAAA()

{

//….

}

This is the synchronization method, so which object is synchronized locked at this time? What it locks is the object that calls this synchronized method. In other words, when an object P1 executes this synchronization method in different threads, they will form mutual exclusion to achieve a synchronization effect. However, another object P2 generated by the Class to which this object belongs can arbitrarily call this method with the

synchronized keyword added.

The sample code above is equivalent to the following code:

public void methodAAA()

{

synchronized (this) // (1)

{

//…..

}

}

What does this in (1) refer to? It refers to the object that calls this method, such as P1. It can be seen that the essence of the synchronization method is to apply synchronized to the object reference. ——Only the thread that has obtained the P1 object lock can call the synchronization method of P1. As far as P2 is concerned, the P1 lock has nothing to do with it. The program may also get rid of the control of the synchronization mechanism in this situation. Causing data chaos: (

2. Synchronization block, the sample code is as follows:

public void method3(SomeObject so)

{

synchronized(so)

{

//…..

}

}

At this time, the lock is the so object. Whoever gets the lock can run the code controlled by it. When there is a clear object as the lock, you can write the program like this, but when there is no clear object.
The exact object acts as a lock. When you just want to synchronize a piece of code, you can create a special instance variable (it must be an object) to act as a lock:

class Foo implements Runnable

{

      private byte[] lock = new byte[0]; // Special instance variable

                                                                        use using using ‐                     through using ’ through ’ s ’ through using using using ’s ’ through ’s ’ through ‐ to ‐ ‐‐‐‐ } new byte[0];                                                              

Note: Zero A length byte array object will be more economical to create than any object - look at the compiled bytecode: generating a zero-length byte[] object requires only 3 opcodes, while Object lock

= new Object() requires 7 lines of operation code.

3. Apply synchronized to static function, the sample code is as follows:


Class Foo

{

     public synchronized static void methodAAA()                                                                       V Public void methodbbbb () {

Synchronized (foo.class) // Class Literal It has the same effect as the synchronized static function. The lock obtained is very special. It is the class (Class) to which the object currently calling this method belongs, rather than a specific object generated by this Class. .

I remember reading in the book "Effective Java" that using Foo.class and P1.getClass() for synchronization locks is not the same. You cannot use P1.getClass() to achieve the purpose of locking this Class. . P1 refers to the object generated by class Foo.

It can be inferred: If a synchronized static function A is defined in a class, and a synchronized instance function B is also defined, then the same object Obj of this class will access the A and B methods respectively in multiple threads. , will not constitute synchronization 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.

The summary is as follows:

Understanding which object is locked by synchronized can help us design safer multi-threaded programs.

There are also some techniques that can make our synchronous access to shared resources more secure:


1. Define the private instance variable + its get method instead of the public/protected instance variable. If the variable is defined as public, the object can be obtained directly from the outside world and change it, bypassing the control of the synchronization method. This is also one of the standard implementation methods of JavaBean.

2. If the instance variable is an object, such as an array or ArrayList, then the above method is still unsafe, because when the external object gets the reference of the instance object through the get method and points it to another object, then this private The variables have also changed, which is very dangerous. At this time, you need to add synchronized synchronization to the get method, and only return the clone() of this private object - in this way, what the caller gets is a reference to the object copy


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:Java Socket ProgrammingNext article:Java Socket Programming