Although multithreaded programming greatly improves efficiency, it also brings some hidden dangers. For example, two threads simultaneously inserting different data into a database table may result in the same data being inserted into the database. Today we are going to discuss thread safety issues and what mechanisms Java provides to address them. Source: github.com/limingios/n…
synchronized & Volatile
JSR133 www.cs.umd.edu/~pugh/java/… FIFO(First Input First Output) simply means First in First out.
- What is an object lock
Lock, lock is also called object method for an object instance, it is only in the object of a memory location to declare whether a identifies the object have locks, all it will only to lock the current object, and will not be any influence on other object instance lock, different access to the same object is synchronized modified method does not block,
- What is class code
Class lock is to lock the whole class, when more than one thread to declare the object of the class will be blocked, until the object that owns the class lock is destroyed or actively released the class lock, this time in the blocked thread is selected to hold the class lock, declare the object of the class. Other threads continue to block.
(above Baidu), that is, no matter how many objects, how many objects, sharing a much, and only a, no matter how to call, will be synchronized
synchronized
Before we look at the use of the synchronized keyword, let’s take a look at the concept of a mutex. As the name suggests, a lock that provides mutually exclusive access.
1. A simple example: if a mutex is added to a critical resource, while one thread accesses the critical resource, the other threads have to wait. 2. In Java, every object has a lock marker (monitor). When multiple threads access an object at the same time, the thread can only access the object if it has acquired the lock of the object. 3. In Java, the synchronized keyword can be used to mark a method or code block. When a thread calls the object’s synchronized method or accesses the synchronized code block, the thread obtains the lock of the object, and other threads cannot access the method temporarily. The thread will release the lock only after the method or block finishes executing, and other threads can execute the method or block.
But there are a few caveats:
1) When a thread is accessing the synchronized methods of an object, other threads cannot access the synchronized methods of that object. The reason is simple, because an object has only one lock, and when one thread acquires the lock of the object, other threads cannot acquire the lock of the object, so they cannot access other synchronized methods of the object.
2) When one thread is accessing the synchronized methods of an object, other threads can access the non-synchronized methods of the object. Access to a non-synchronized method does not require acquiring the lock of the object. If a method does not use the synchronized keyword, it does not use critical resources, and other threads can access the method.
3) If one thread A needs to access the synchronized fun1 method of object1 and another thread B needs to access the synchronized fun1 method of object2, even though object1 and Object2 are of the same type, thread-safety problems will not occur. Because they access different objects, there is no mutual exclusion problem.
For synchronized methods or blocks of synchronized code, when an exception occurs, the JVM automatically releases the lock held by the current thread, so there is no deadlock due to the exception
volatile
Once a shared variable (a member variable of a class, a static member variable of a class) is volatile, there are two levels of semantics:
1) It ensures visibility when different threads operate on the variable, i.e. one thread changes the value of a variable and the new value is immediately visible to other threads.
2) Forbid instruction reordering.
Synchronized prevents multiple threads from executing a piece of code at the same time, which can affect program execution efficiency. Volatile is better than synchronized in some cases. However, it is important to note that volatile is not a substitute for synchronized. The volatile keyword does not guarantee atomicity. In general, two conditions must be met to use volatile:
1) Write operations to variables do not depend on the current value
2) This variable is not included in invariants with other variables
In effect, these conditions indicate that the valid values that can be written to volatile variables are independent of the state of any program, including the current state of the variables.
ReentrantLock
Prior to JDK5.0, the performance of reentrant lock was much better than that of synchronized, and after JDK6.0, the performance of synchronized was much better than that of JDK6.0. However, reentrant lock can completely replace synchronized. In addition, reentrant locks also come with a series of high performance UBFF: interruptible response, lock application wait time limit, fair lock. It can also be used in combination with Condition to make it even more intense.
- Fair lock
The fair lock obtains the lock from the first node in the synchronization queue every time. The fair lock obtains the lock from the first node in the synchronization queue every time to ensure the absolute sequence of resource requests. Fair lock To ensure the absolute sequence in time, frequent context switching is required. Non-fair lock reduces context switching and performance overhead. Therefore, by default, ReentrantLock selects an unfair lock to reduce some context switches and ensure higher throughput.
- Not fair lock
An unfair lock is not necessarily the case. It is possible that the thread that released the lock can acquire it again. A fair lock may cause the thread that just released the lock to acquire the lock the next time, and other threads may never be able to acquire the lock, resulting in “starvation”.
Provides a FIFO – based queue that can be used to build locks or other related synchronization devices. The synchronizer (hereinafter referred to as the synchronizer) uses an int to represent state and is expected to be the basis for most synchronization requirements. The method used is inheritance. Subclasses manage their state by inheriting the synchronizer and implementing its methods, using methods like acquire and release to manipulate state. However, the manipulation of state in a multithreaded environment must be atomic, so subclasses need to manipulate state using the following three methods provided by the synchronizer:
java.util.concurrent.locks.AbstractQueuedSynchronizer.getState()
java.util.concurrent.locks.AbstractQueuedSynchronizer.setState(int)
java.util.concurrent.locks.AbstractQueuedSynchronizer.compareAndSetState(int, int)
Copy the code
The subclass recommendation is defined as the internal class of the custom synchronizer. The synchronizer itself does not implement any synchronization interface, it simply defines a number of acquire and other methods for use. This synchronizer can be used in either exclusive or shared mode. When it is defined as an exclusive mode, other threads are prevented from accessing it, whereas shared mode can be successful for multiple threads accessing it.
Synchronizer is the key to realize lock. Synchronizer is used to realize lock semantics, and then synchronizers are aggregated in lock implementation. The lock API is user-oriented, defining common behaviors that interact with the lock, and the specific actions that each lock needs to perform are done through these behaviors (e.g., allowing two threads to lock and excluding more than two threads), but implementation relies on the synchronizer. Synchronizer is oriented towards thread access and resource control. It defines whether a thread can obtain a resource and queueing the thread. Locks and synchronizers nicely separate the areas of concern of both, and synchronizers can be applied to other synchronization facilities besides locks (including locks) strictly speaking.
AbstractQueuedSynchronizer is also known as a queue synchronizer (hereafter referred to as “AQS), it is used to construct the lock or other synchronous component based framework through an internal member variables of type int the state to control the synchronization state, when the state = 0, then no thread lock has a Shared resource, When state=1, it means that some threads are currently using shared variables, and other threads must join the synchronization queue for waiting. AQS uses the internal class Node to form the synchronization queue of FIFO to complete the queuing work of thread obtaining locks. At the same time, ConditionObject is used to construct the waiting queue. When Condition calls wait(), the thread is added to the wait queue, and when Condition calls signal(), the thread is moved from the wait queue to the move synchronization queue for lock contention. Note that there are two types of queues involved: one is a synchronous queue, in which a thread requesting a lock will join the synchronous queue to wait, and the other is await queue (there may be more than one), in which the lock is released by calling await() on Condition.
PS: more theory, focus on a good look, the source code to share the PDF, the official website on the thread this introduction, people have been translated into Chinese, it is easy to understand.