Java thread security, java thread
I have encountered a lot of questions about thread security recently, such:
Synchronized andWhat is the difference between volatile and volatile?
What is the difference between StringBuilder and StringBuffer?
What is the difference between HashMap and HashTable?And so on ......
The answer to these questions is about thread security. First, we need to have a concept of thread security.
Thread security and thread security:
Thread SecurityWhen multiple threads run concurrently, when a thread accesses a data of the class, it uses a lock mechanism to protect data until the current thread has read the data and released the lock, other threads can continue to be used. We think this is thread-safe.
With thread security, threads are naturally insecure,Thread SecurityWhen multiple threads run concurrently, the data is not protected, and multiple threads may modify or use a certain data, resulting in incorrect data, that is, dirty data.
After learning about the basic concepts, I will introduce a great god to describe thread security from the aspects of Java Memory Model and thread synchronization mechanism.
Java Memory Model
Different platforms have different memory models, but the jvm memory model specifications are uniform. In fact, java's multi-thread concurrency problems will eventually be reflected in the java memory model. The so-called thread security is not to control the orderly access or modification of a resource by multiple threads. To sum up the java memory model, we need to solve two main problems: visibility and orderliness.
Visibility:Multiple Threads cannot communicate with each other. Communication between them can only be performed through shared variables. The Java Memory Model (JMM) specifies that the jvm has the primary memory, which is shared by multiple threads. When a new object is created, it is also allocated to the primary memory. Each thread has its own working memory, which stores copies of some objects in the primary memory, of course, the thread's working memory size is limited. When a thread operates an object, the execution sequence is as follows:
(1) copy the variable from the primary memory to the current working memory (read and load)
(2) execute the code and change the value of shared variables (use and assign)
(3) Use the working memory data to refresh the content related to the primary storage (store and write)
When a shared variable has copies in the working memory of multiple threads, if a thread modifies the shared variable, other threads should be able to see the modified value, this is the visibility of multithreading.
Orderliness:When a thread references a variable, it cannot be referenced directly from the main memory. If the variable does not exist in the thread's working memory, a copy is copied from the main memory to the working memory, after completion, the thread references this copy. When the same thread references this field again, it is possible to obtain a copy of the variable from the primary storage (read-load-use) Again, or directly reference the original copy (use ), that is to say, the order of read, load, and use can be determined by the JVM implementation system.
The thread cannot directly assign values to fields in the primary memory. It will assign the values to the variable copy (assign) in the working memory ), after the completion, the copy of the variable will be synchronized to the primary storage area (store-write). As to when the synchronization will pass, it is determined by the JVM implementation system. with this field, the field is assigned to the working memory from the main memory. This process is read-load. After completion, the thread will reference this variable copy.
For exampleExample 1, There is a variable x = 10, a thread executes x = x + 1 operation, B thread executes x = X-1 operation, when the two threads run at the same time, the value of x is not sure, it may be 9 or 11, which is the result of the unpredictable order of multi-thread concurrent execution. Therefore, to ensure thread security, to ensure the orderly execution of thread a and thread B, and the executed operations must beAtomic operation.
Atomic operation:When multiple threads access shared resources, all other processes (threads) cannot access the same resources at the same time. Atomic operation does not require synchronized, which is a common topic in Java multi-thread programming. The so-called atomic operation is an operation that will not be interrupted by the thread scheduling mechanism. Once this operation starts, it will continue to run until the end, and there will be no context switch (switch to another thread) in the middle ).
So how can we ensure the orderliness and visibility of thread execution?
Synchronized keyword
SynchronizedThe keyword can solve the issue of orderliness and visibility. It ensures that multiple threads are mutually exclusive. When a piece of code modifies the shared variable, this piece of code becomes a mutex or a critical section, to ensure the correctness of shared variables, synchronized indicates the critical section.
Common usage:
Java code
Synchronized (lock) {critical code} // example: public synchronized void method () {} public static synchronized void method (){}
Whether the synchronized keyword is added to a method or an object, the object is used as a lock. In theory, each object can be a lock.
In the case of public synchronized void method (), the lock is the object of the method. Similarly, if the method is public static synchronized void method (), the lock is the class of the method.
The synchronized keyword has two types of lock objects. One is locking the object, the other is locking the class, and locking the class, the class lock applies to all objects in the class, the object lock only locks a specified object of this class. Other objects of this class can still use the synchronized method that has locked the previous object.
For example, if there is only one ticket at the station, clerk A and Clerk B will issue the ticket at the same time and execute the public synchronized void Merge () method, then the result will appear. The remaining number of votes is (-1) this is the problem caused by the object lock. Other objects can still use this method;
After the merge method is added with static, the lock object is the class. For Clerk A and Clerk B, the business must be operated in order, in this way, the remaining number of votes is no longer counted.
When an object is locked, it makes sense to share it with multiple threads. This also draws a conclusion: Non-thread security! = Insecure.
For example, ArrayList is thread unsafe, but it does not mean that ArrayList is not used in the case of multithreading. If every thread has a new ArrayList object, that is, the object is not shared, there is no resource competition between threads, so there is no security problem during multi-thread execution.
Each lock object has two queues: one is a ready queue and the other is a blocking queue. The ready queue stores the thread to obtain the lock, and the blocking queue stores the blocked thread, after a thread is awakened, it enters the ready queue and waits for cpu scheduling.
A thread executes the critical code process as follows:
1. Obtain the synchronization lock
2. Clear the working memory
3. Copy the variable copy from the primary storage to the working memory.
4. calculate these variables
5. Write the variable back to the primary memory
6. Release the lock
It can be seen that synchronized not only ensures the concurrency orderliness of multiple threads, but also ensures the memory visibility of multiple threads.
Producer/consumer modelThis is a typical synchronization lock problem. In addition to the mutex operation, multi-thread execution usually involves mutual collaboration between threads.
For example, robot A is responsible for building A car. After the car is built, it is placed in the warehouse. Each time, only one car can be placed in the warehouse.
(1) At first, robot A was run and executed the make Method for car building. After the car was built and placed in the warehouse, it did not immediately shut down (release the lock), but woke up (notify) the B-host who is preparing to go to work (blocking Queue) and stops working (entering the blocking Queue)
(2) machine B gets a synchronization lock and starts to take the created car out of the warehouse for sale at work. After the car is transported out, it does not slide immediately, instead, it woke up robot A, who just got off work, to continue making cars (naked exploitation, I also want to sell cars ).
(3) robot A finds that the car in the warehouse has been taken away, and after receiving the task, he can only continue to build the car. After the car is built, the B robot is called back.
(4) B robots sell cars and wake up machine A's man-made cars.
......
It can be seen that, under the Action of synchronous locks, it is pleasant to build a car, sell a car, make a car, and sell a car in an orderly manner.
Next we will talk about another Keyword:Volatile
Volatile keywords
Volatile is also a method for Java synchronization, but it is a little weaker than the synchronized lock. It can only ensure the visibility of multi-thread execution, but cannot guarantee the orderliness.
The principle is that you do not need to copy a copy from the primary memory to the working memory, but directly modify the data in the primary memory, so that other threads can immediately see the data modification. Therefore, volatile must be used in scenarios where the arm synchronized is small and is often used for direct assignment, suchExample 1Is not applicable.
Note that although the synchronized lock is good, it cannot be used for multiple purposes and affects the execution efficiency. The thread blocking the queue will constantly try to obtain the lock, consuming performance.