When a Java language keyword is used to modify a method or a code block, it can ensure that at most one thread executes the code at the same time.
1. When two concurrent threads access this synchronized(this) synchronized code block in the same object object, only one thread can be executed within one time. Another thread must wait for the current thread to execute this code block before it can execute the code block.
2. However, when one thread accesses a synchronized (this) synchronization code block of an object, another thread can still access the non-synchronized (this) synchronization code block in that object.
3. It is particularly critical that when a thread accesses a synchronized (this) synchronization code block of an object, other threads will block access to all other synchronized (this) synchronization code blocks in the object.
4. The third example also applies to other synchronous code blocks. That is, when a thread accesses a synchronized(this) synchronization code block of an object, it obtains the object lock of this object. As a result, other threads access to all synchronous code parts of the object object is temporarily blocked.
5. The above rules also apply to other object locks.
Give an example:
1. When two concurrent threads access this synchronized(this) synchronized code block in the same object object, only one thread can be executed within one time. Another thread must wait for the current thread to execute this code block before it can execute the code block.
package ths;public class Thread1 implements Runnable { public void run() { synchronized(this) { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); } } } public static void main(String[] args) { Thread1 t1 = new Thread1(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } }result:
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 one thread accesses a synchronized (this) synchronization code block of an object, another thread can still access the non-synchronized (this) synchronization code block in that 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(); } } result:
t1: 4
t2: 4
t1: 3
t2: 3
t1: 2
t2 : 2
t1: 1
t2: 1
t1: 0
t2: 0
3. It is particularly critical that when a thread accesses a synchronized (this) synchronization code block of an object, other threads will block access to all other synchronized (this) synchronization code blocks in the object.
//Modify Thread2.m4t2() method: public void m4t2() { synchronized(this) { int i = 5; while( i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } }result:
t1: 4
t1: 3
t1: 2
t1: 1
t1: 0
t2: 4
t2: 3
t2 : 2
t2: 1
t2: 0
4. The third example also applies to other synchronous code blocks. That is, when a thread accesses a synchronized(this) synchronization code block of an object, it obtains the object lock of this object. As a result, other threads access to all synchronous code parts of the object object is temporarily blocked.
//Modify the Thread2.m4t2() method as follows: public synchronized void m4t2() { int i = 5; while( i-- > 0) { System.out.println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } result:
t1: 4
t1: 3
t1: 2
t1: 1
t1: 0
t2: 4
t2: 3
t2 : 2
t2: 1
t2: 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) { //Use object lock 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(); } }result:
Although thread t1 obtains an object lock on the Inner, since thread t2 accesses the asynchronous part in the same Inner. Therefore, the two threads do not interfere with each other.
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
Now put synchronized in front of Inner.m4t2():
private synchronized void m4t2() { int i = 5; while(i-- > 0) { System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); try { Thread.sleep(500); } catch(InterruptedException ie) { } } }result:
Although threads t1 and t2 access two unrelated parts of the same Inner object, because t1 first obtains the object lock to the Inner, t2's access to Inner.m4t2() is also blocked because m4t2() is a synchronization method in Inner.
t1: Inner.m4t1()=4
t1: Inner.m4t1()=3
t1: Inner.m4t1()=2
t1: Inner.m4t1()=1
t1: Inner.m4t1()=0
t2: Inner.m4t2()=4
t2: Inner.m4t2()=3
t2: Inner.m4t2()=2
t2: Inner.m4t2()=1
t2: Inner.m4t2()=0
Article 2:
synchronized keyword, which includes two usages: the synchronized method and the synchronized block.
1. Synchronized method: Declare the synchronized method by adding the synchronized keyword to the method declaration. like:
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 before it can be executed. 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 it returns from the method. The blocked thread can obtain the lock and re-enter the executable state. This mechanism ensures that at the same time, for each class instance, at most one of all member functions declared synchronized is in an executable state (because at most one can obtain the lock corresponding to the class instance), thus effectively avoiding access conflicts of class member variables (as long as all possible methods to access class member variables are declared synchronized).
In Java, not only class instances, but each class also corresponds to a lock, so we can declare the static member function of the class as synchronized to control its access to the static member variables of the class.
The disadvantage of synchronized method: Declaring a large method as synchronized will greatly affect efficiency. Typically, if the thread class's method run() is declared as synchronized, since it has been running throughout the life of the thread, it will cause it to never succeed in any synchronized method of this class. Of course we can solve this problem by putting the code that accesses the class member variables into a special method, declaring it as synchronized, and calling it in the main method, but Java provides us with a better solution, that is, the synchronized block.
2. Synchronized block: Declare the synchronized block through the synchronized keyword. The syntax is as follows:
synchronized(syncObject) { //Code that allows access control} The synchronized block is a code block in which the code must obtain a lock of the object syncObject (as mentioned earlier, it can be a class instance or class) before it can be executed. The specific mechanism is the same as described above. Since it can be targeted at any code block and locked objects can be specified at any time, it is more flexible.
Some understandings of synchronized(this) <br />1. When two concurrent threads access this synchronized(this) synchronized code block in the same object, only one thread can be executed within one time. Another thread must wait for the current thread to execute this code block before it can execute the code block.
2. However, when one thread accesses a synchronized (this) synchronization code block of an object, another thread can still access the non-synchronized (this) synchronization code block in that object.
3. It is particularly critical that when a thread accesses a synchronized (this) synchronization code block of an object, other threads will block access to all other synchronized (this) synchronization code blocks in the object.
4. The third example also applies to other synchronous code blocks. That is, when a thread accesses a synchronized(this) synchronization code block of an object, it obtains the object lock of this object. As a result, other threads access to all synchronous code parts of the object object is temporarily blocked.
5. The above rules also apply to other object locks.
How to use synchronized in java
For example: an object is like a big house, the door is always open. There are many rooms in the house (that is, the method).
These rooms have locked (synchronized method), and are not locked (normal method). There is a key at the door, which can open all locked rooms.
In addition, I compare all threads that want to call the object method to people who want to enter a room in this house. There are only so many things, let’s see how these things work.
Here we first clarify our prerequisites. The object has at least one synchronized method, otherwise what is the point of this key? Of course, there will be no such topic for us.
A man wanted to enter a locked room. He came to the door of the house and saw the key there (it means no one else wants to use the locked room yet). So he walked up and got the keys and used the rooms as he planned. Be aware that he will return the key immediately after using the locked room every time. Even if he wants to use two locked rooms in a row, he will return the keys to retrieve them. Therefore, the principle of using a key in ordinary cases is: "Borrow as you use, and return it as soon as you use it."
At this time, other people can use those unlocked rooms without restrictions. One person can use one room, and two people can use one room, without restrictions. But if someone wants to enter a locked room, he has to run to the gate to take a look. Of course, if you have the key, you will leave. If you don’t have it, you can only wait. If many people are waiting for this key, who will get the key first after it is returned? Not guaranteed. Like the guy in the previous example who wanted to use two locked rooms in a row, if there were other people waiting for the keys in the middle, there was no guarantee that this guy would get it again. (The JAVA specification clearly states that it is not guaranteed in many places, such as how long it takes for Thread.sleep() to return to run after rest, the thread with the same priority is executed first, and which thread in the waiting pool will be given priority after the lock to access the object is released, etc. I think the final decision is in the JVM. The reason why it is not guaranteed is because when the JVM makes the above decision, it is by no means simply making a judgment based on one condition, but based on many articles.
Because there are too many judgment conditions, if you say it, it may affect the promotion of JAVA, or it may be due to intellectual property protection. SUN gave me a promise and got through it. There is nothing wrong with it. But I believe these uncertainties are not entirely uncertain. Because the computer itself runs according to instructions. Even if the phenomenon seems random, it is actually regular. Anyone who has studied computers knows that the scientific name of random numbers in computers is pseudo-random numbers, which are written by people using certain methods, and they just look random. In addition, perhaps it is because it is too difficult to make sure and not very meaningful, so if you are not sure, you are not sure. )
Let’s take a look at the synchronization code block. There is a slight difference from the synchronization method.
1. In terms of size, the synchronization code block is smaller than the synchronization method. You can think of the synchronization code block as a space in an unlocked room separated by a locked screen.
2. The synchronization code block can also artificially specify the key of obtaining a certain other object. Just like specifying which key to unlock the screen, you can use the key of this room; you can also specify that the key of another house can open it. In this way, you have to run to another house to bring that key and use the key of that house to open the locked screen of this house.
Remember that the key to that other house you have obtained does not affect other people entering the room without locks in that house.
Why use synchronous code blocks? I think it should be like this: First of all, the synchronization part of the program has a lot of impact on the operation efficiency, and a method is usually to create some local variables first, and then do some operations on these variables, such as operations, display, etc.; and the more code covered by synchronization, the more serious the impact on efficiency. Therefore, we usually try to narrow its impact.
How to do it? Synchronize code blocks. We only synchronize the synchronization places in one method, such as operations.
In addition, the feature of synchronous code blocks that can specify keys has an additional advantage, which is that it can occupy the keys of an object within a certain period of time. Do you remember the principles of using keys in ordinary situations mentioned earlier? It's not the ordinary situation now. The key you obtained is not never returned, but is returned only when you exit the synchronous code block.
I also used the guy in front who wanted to use two locked rooms in a row to make an example. How can I continue to use another one after using it? Use synchronous code blocks. First create another thread, make a synchronous 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 the house when entering 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, or even sleep (10*60*1000), and there are still 1,000 threads waiting for this key at the door. Very enjoyable.
Here we will 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 synchronous content, the key is still there. The key will not be returned until it runs again and completes all synchronous content. Remember, that guy was just tired of working, so he went to take a break, and he didn't finish what he was going to do. In order to avoid others entering the room and making a mess, he has to wear the only key on his body even when he is sleeping.
Finally, some people may ask, why do you need a key to open instead of a key and a door? I think this is purely because of complexity. Of course, one key and one door are safer, but it will involve many problems. The generation, storage, acquisition, return, etc. of keys. Its complexity may increase in geometrical sequences with the increase of the synchronization method, which seriously affects efficiency. This is also a trade-off. How undesirable is to increase the safety a little bit, resulting in a significant reduction in efficiency.
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 example above, in order to create a time difference, that is, the opportunity to make an error, Thread.sleep(10) is used.
Java's support and synchronization mechanism for multithreading is very popular. It seems that using the synchronized keyword can easily solve the problem of multithreaded shared data synchronization. What exactly? It is also necessary to have an in-depth understanding of the role of synchronized keywords before you can make a conclusion.
In general, the synchronized keyword can be used as a modifier of the function or as a statement within the function, which is the synchronization method and synchronization statement block that are usually mentioned. If you classify it more carefully, synchronized can act on instance variables, object references, static functions and class literals (class name literal constants).
Before we elaborate further, we need to clarify a few points:
A. 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 function as a lock, and the synchronization method is likely to be even more likely to be
Object access to his thread.
B. Each object has only one lock associated with it.
C. Implementing synchronization requires a lot of system overhead as a cost and may even cause deadlocks, so try to avoid unnecessary synchronization control.
Next, let’s discuss the impact of synchronized using different places on the code:
Assuming 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 example 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 to call this synchronous method object. That is to say, when an object P1 executes this synchronization method in different threads, mutual exclusion will be formed between them to achieve the effect of synchronization. However, another object P2 generated by Class to which this object belongs can arbitrarily call this method with the synchronized keyword added.
The above example code is equivalent to the following code:
public void methodAAA(){synchronized (this) // (1){ //…..}}(1) What does this at the point mean? It refers to the object that calls this method, such as P1. It can be seen that the synchronization method is essentially to apply synchronized to the object reference. Only the thread that has obtained the P1 object lock can call the P1 synchronization method. For P2, 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 confusion: (
2. Synchronize blocks, the sample code is as follows:
public void method3(SomeObject so){ synchronized(so) { //….. }}At this time, the lock is the object of so. Whoever gets the lock can run the code it controls. When there is a clear object as a lock, you can write the program like this, but when there is no clear object as a lock and just want a piece of code to synchronize, you can create a special instance variable (it has to 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: Zero-length byte array objects are more economical than any object to create a compiled byte code: only 3 opcodes are required to generate a zero-length byte[] object, while Object lock= new Object() requires 7 opcodes.
3. Use synchronized to static function, the example 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 a lock. It has the same effect as the synchronized static function. The lock obtained is very special. It is the class to which the object currently calling this method belongs (Class, not a specific object generated by this Class).
I remember that in the book "Effective Java", I saw that using Foo.class and P1.getClass() as synchronous locks is different, and P1.getClass() cannot be used to achieve the purpose of locking this Class. P1 refers to an object generated by the Foo class.
It can be inferred that if a class defines a synchronized static function A and a synchronized instance function B, then the same object Obj of this class will not constitute synchronization when accessing two methods A and B in multiple threads, because their locks are different. The lock of method A is the object Obj, while the lock of B is the Class to which Obj belongs.
The summary is as follows:
Finding out which object synchronized locks can help us design safer multi-threaded programs. There are also some tips to make synchronous access to shared resources more secure:
1. Define the instance variable of private + its get method, instead of the instance variable of public/protected. If a variable is defined as public, the object can bypass the control of the synchronization method and directly obtain it and change it. This is also one of the standard implementation methods of JavaBean.
2. If the instance variable is an object, such as an array or an ArrayList, then the above method is still unsafe, because when an external object gets the reference to the instance object through the get method and points it to another object, then the private variable will change, which is not very dangerous. At this time, you need to add synchronized to the get method, and only return the clone() of this private object, so the caller gets the reference to the object copy
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.