In multi-threaded programming, the most critical and most concerning issue should be synchronization. This is a difficult point and the core.
From the synchronized and volatile versions of jdk to the Lock interface in the java.util.concurrent.locks package provided in jdk 1.5 (which implements ReadLock, WriteLock, and ReentrantLock), the implementation of multi-threading is also maturing step by step. change.
Synchronization, what mechanism is it controlled through? The first reaction is locks. You should have been exposed to this when learning operating systems and databases. In a Java multi-threaded program, when multiple programs compete for the same resource, in order to prevent resource corruption, an object lock is assigned to the first thread to access the resource, and the later ones need to wait for the release of the object lock.
Yes, Java thread synchronization is most concerned about the use of shared resources.
First let’s understand some shared resources of threads.
Understand which thread-shared data needs to be coordinated from the JVM:
1. Instance variables stored in the heap; 2. Class variables saved in the method area.
When the Java virtual machine loads a class, each object or class will be associated with a monitor to protect the object's instance variables or class variables; of course, if the object has no instance variables or class variables, Without variables, the monitor monitors nothing.
In order to realize the mutual exclusivity of the monitor mentioned above, the virtual machine associates a lock (also called invisible lock) for each object or class. Here, it is explained that class locks are also obtained through object locks. This is achieved because when a class is loaded, the JVM will create an instance of java.lang.Class for each class; therefore, when the object is locked, the class object of this class is also locked.
In addition, a thread can lock an object multiple times, which corresponds to multiple releases; it is a lock calculator provided by the JVM for each object lock. The last lock is added 1, the corresponding decrement is 1, and when the value of the calculator is 0, it is released. This object lock is used by the monitor inside the JVM and is automatically generated by the JVM. All programmers do not need to add it themselves.
After introducing the synchronization principle of Java, we get to the point. Let’s first talk about the use of synchronized, and other synchronization will be introduced in subsequent chapters.
Let’s try running an example first.
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * */ public class TestThread extends Thread{ private int threadnum; public TestThread(int threadnum) { this.threadnum = threadnum; } @Override public synchronized void run() { for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } public static void main(String[] args) throws Exception { for(int i=0; i<10; i++){ new TestThread(i).start(); Thread.sleep(1); } } }
Run results:
NO.0:887 NO.0:888 NO.0:889 NO.0:890 NO.0:891 NO.0:892 NO.0:893 NO.0:894 NO.7:122 NO.7:123 NO.7:124
The above is just a fragment to illustrate a problem.
Careful children's shoes will find that NO.0:894 is followed by NO.7:122, which means that it does not start from 0 to 999.
It is said that synchronized can implement synchronized methods or synchronized blocks. Why can't it work here?
Let’s first analyze the synchronization mechanism. Synchronization is achieved through locks. So in the above example, what objects or types are locked? There are two variables in it, one is i and the other is threadnum; i is internal to the method, and threadnum is private.
Let’s take a look at the synchronized operating mechanism:
In a Java program, when using a synchronized block or synchronized method, this area is marked for monitoring; while when the JVM is processing the program, when a program enters the monitoring area, it The object or class is automatically locked.
So in the above example, after the synchronized keyword is used, what is locked?
When the synchronized method is used, the instance object itself that calls the method is locked as the object lock. In this example, 10 threads have their own TestThread class objects created by themselves, so the object lock acquired is also their own object lock and has nothing to do with other threads.
To implement method locking, a shared object must be locked.
Modify the above example and take another look:
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * */ public class TestThread extends Thread{ private int threadnum; private String flag; //标记 public TestThread(int threadnum,String flag) { this.threadnum = threadnum; this.flag = flag; } @Override public void run() { synchronized(flag){ for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } } public static void main(String[] args) throws Exception { String flag = new String("flag"); for(int i=0; i<10; i++){ new TestThread(i,flag).start(); Thread.sleep(1); } } }
A shared flag is also added. Then synchronize the flag flag through the synchronized block; this meets the conditions for locking the shared object.
Yes, the running results have come in order.
Through the synchronized block, specify the object lock to achieve the purpose of synchronization. Is there any other way to achieve this through the synchronized method?
According to the principle of synchronization: If you can obtain a shared object lock or class lock, synchronization can be achieved. So can we achieve it by sharing a class lock?
Yes, we can use static synchronization methods. According to the characteristics of static methods, it can only be called by the class object itself, and cannot be called by instantiating a class object. Then if the lock of this static method is obtained, this class lock is obtained, and these class locks are all TestThread class locks, and the purpose of obtaining the shared class lock is achieved.
The implementation code is as follows:
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * * @author ciding * @createTime Dec 7, 2011 9:37:25 AM * */ public class TestThread extends Thread{ private int threadnum; public TestThread(int threadnum) { this.threadnum = threadnum; } public static synchronized void staticTest(int threadnum) { for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } public static void main(String[] args) throws Exception { for(int i=0; i<10; i++){ new TestThread(i).start(); Thread.sleep(1); } } @Override public void run(){ staticTest(threadnum); } }
The running results are the same as in the second example.
The above content mainly explains two issues: synchronization block and synchronization method.
1, Synchronization block: The object lock acquired is the flag object lock in synchronized(flag).
2, Synchronous method: What is obtained is the class object to which the method belongs and the class object lock.
Static synchronization method, since multiple threads will share it, it will definitely be synchronized.
Instead of a static synchronization method, it will only be synchronized in singleton mode.
For more explanations on the basic usage of the synchronized keyword in Java multi-threaded programming, please pay attention to the PHP Chinese website!