Thread Safety and lock optimization

Source: Internet
Author: User
Tags cas instance method mutex

The concept of thread safety is limited to the premise that shared data access exists between multiple threads, because if a piece of code does not share data with other threads at all, then from a thread-safe point of view, whether the program is executed serially or multithreaded is completely indistinguishable from it.

The degree of thread Safety: immutable, absolute thread-safe, relative thread-safe, thread-compatible, and thread-antagonistic.

1. Non-volatile

Immutable objects must be thread-safe, as long as an immutable object is properly constructed (without this reference escaping), its visible state will never change, and will never see it in an inconsistent state in multiple threads. such as the integer class, the internal state variable value is defined as final to guarantee that the state is unchanged.

2. Absolute thread Safety

To achieve whatever environment is running, the caller does not need any additional synchronization measures. Labeling yourself in the Java API is a thread-safe class, most of which are not absolutely thread-safe.

3. Relative Thread safety

In the sense of thread safety, it is necessary to ensure that the individual operation of this object is thread-safe and that there is no need for additional safeguards at the time of invocation, but for successive invocations in a particular order, it may be necessary to use an additional synchronization method at the caller's side to ensure the correctness of the call. A collection of Synchronizedcollection () method wrappers such as vectors, HashTable, collections.

4. Thread-compatible

The object itself is not thread-safe, but can be used correctly by the caller to ensure that the object is safe to use in a concurrent environment, most of the Java API classes are thread-compatible, such as ArrayList, HashMap.

5. Thread antagonism

Code that can be used concurrently in a multithreaded environment, regardless of whether the caller has taken synchronization measures. Harmful, should try to avoid, such as the thread class of suspend () and the Resume () method, if two threads hold a thread object at the same time, an attempt to go to the thread, an attempt to recover the threads, and concurrently, regardless of whether the call is synchronized, the target thread has a deadlock risk, So these two methods have been declared obsolete.

Thread-Safe Implementation methods:

1. Mutex synchronization, synchronous refers to the concurrent access of multiple threads of shared data, to ensure that the shared data at the same time only by one (or some, when using semaphores) thread use, mutual exclusion is a means to achieve synchronization, the critical area, mutual exclusion and semaphore are the main mutually exclusive implementation mode.

In Java, the most basic means of synchronization is the Synchronized keyword, the synchronized keyword after compiling, the synchronization block will be formed before and after the Monitorenter and monitorexit the two bytecode instructions, These two bytecode directives require a parameter of type reference to indicate the object to lock and unlock. If an object parameter is explicitly specified, it is the object's reference, and if not explicitly specified, the corresponding object instance or class object will be taken as the lock object according to whether the synchronized modifies the instance method or the classes method.

When executing the monitorenter instruction, first try to get the lock of the object, if the object is not locked, or when the front thread already owns the lock of the object, the lock counter is added 1, corresponding, when the monitorexit instruction is executed, the lock counter is reduced by 1, when the counter is 0 o'clock, The lock is released, and if the lock on the object gets failed, the current thread will block the wait until the object lock is freed by another thread.

The synchronized synchronization block is reentrant to a thread and does not have the problem of locking itself up, and secondly, the synchronization block blocks the entry of the other threads after the thread has finished executing.

Java threads are mapped to the native thread of the system, if you want to block or wake up a thread, need the operating system to help complete, this need to switch from the user state to the kernel mentality, so the state transition takes a lot of processor time, for the code simple synchronization block, State transitions are likely to take longer than user code, so synchronized is a heavyweight operation in Java, and the virtual machine itself performs some optimizations, such as adding a spin-wait process before notifying the operating system to block threads, and avoiding frequent entry into the nuclear mindset.

In addition to synchronized, You can also use the reentrant Lock (Reentrantlock) in the Java.util.concurrent package to achieve synchronization, synchronized is represented as a native syntactic-level mutex, and Reentrantlock as an API-level mutex (lock () and Unlock () method Complete with the try/finally statement block). Reentrantlock adds some advanced features, mainly the following 3 items: Wait can be interrupted, can achieve fair lock, lock can bind multiple conditions.

Wait interruptible: When the thread holding the lock does not release the lock for a long time, the waiting thread can choose to discard the wait and handle other things instead, which is helpful for processing a synchronization block that has a very long execution time.

Fair Lock: When multiple threads are waiting for the same lock, the lock must be acquired sequentially in the order in which the lock is requested, while the non-fair lock is unlocked, and any thread that waits for the lock has the opportunity to acquire the lock, synchronized the lock is unfair, and reentrantlock is not fair by default , but a fair lock can be required through a constructor with a Boolean value.

Locks bind multiple conditions: A Reentrantlock object can bind multiple condition objects at the same time, whereas in synchronized, the Wait () and notify () or Notifyall () methods of the lock object can implement an implied condition, If you want to associate with more than one condition, you have to add a lock, and reentrantlock only needs to call the Newcondition () method multiple times.

Non-blocking synchronization

The main problem with mutex synchronization is the performance issues caused by thread blocking and wake-up, so this synchronization is called blocking synchronization. Mutex synchronization is a pessimistic concurrency policy, always think that as long as not to do synchronization measures, it is certain that there will be problems, regardless of whether the sharing of data is really competing, to be locked up. Based on the development of the hardware instruction set, there is another option: optimistic concurrency strategy based on conflict detection is to operate first, if no other thread requisition shared data, then the operation succeeds, if there is contention for the shared data, there is a conflict, then take other remedial measures (common remedy is to keep retrying, Until successful), because many implementations of this strategy do not need to suspend threads, and are therefore called non-blocking synchronizations.

Compare and Exchange (COMPARE-AND-SWAP)

The CAS directive requires 3 operands, namely the memory location (simply understood as the memory address of the variable, denoted by V), the old expected value (a representation), and the new value (b). When the CAS instruction executes, when and only if v conforms to the old expected value A, the processor updates the value of V with the new value B, otherwise the update is not performed, but the old value of V is returned regardless of whether the value of V is updated, and the entire process is an atomic operation.

ABA problem, CAS is not semantically perfect, there is a logical loophole, if a variable v first read the time is a value, and when the assignment is prepared to check that it is still a value, then CAS think its value has not been changed, but this period may have been a value was changed to B, and later changed back to a. There is a tagged atom reference class atomicstampedstampedreference, can be controlled by the version of the variable to ensure the correctness of the CAs, but in most cases the ABA problem will not affect the correctness of program concurrency, if you need to solve the ABA problem, Instead of using traditional mutex synchronization, you might be more efficient than an atomic class.

Thread-local storage, The Java.lang.ThreadLocal class implements thread-local storage capabilities, and each thread has a Threadlocalmap object in its thread object, which stores a set of Threadlocal.threadlocalhashcode as keys, with local threads changing The amount is worth the K-v value pair, Threadlocal object when the Threadlocalmap access portal of the front thread, each Threadlocal object contains a unique Threadlocalhashcode value, Use this value to retrieve the corresponding local thread variable from the K-V value pair in the thread.

Lock optimization

1. Spin Lock and adaptive spin

The lock state of shared data may only last for a short period of time, and it is not worthwhile to suspend and resume threads during this time. If the physical machine has more than one processor, allowing two or more threads to execute concurrently simultaneously, you can let the thread behind the request lock "wait a while", but not discard the processor execution time, see if the thread holding the lock releases the lock quickly, in order for the thread to wait, to have the thread perform a busy loop (spin), This technique is a spin lock.

JDK 1.6 introduces adaptive spin, spin time is not fixed, from the previous in the same lock spin time and the lock owner's state to determine. If, on the same lock object, the spin wait has just been successfully acquired and the thread holding the lock is running, then the virtual chances are that the spin is likely to succeed again, allowing the spin to wait for a relatively long time, and if, for a lock, the spin is seldom successful, It is possible to omit the spin process later when the lock is acquired to avoid wasting processor resources.

2. Lock removal

Refers to the virtual machine in the instant compiler run, to some code on the requirements of synchronization, but it is detected that there is no possibility of the sharing of data competition of the lock to eliminate, based on the data from the escape analysis support, if a piece of code, all the data on the heap will not escape out of the other threads access, it can be treated as data , which is considered to be thread-private, does not need to be locked synchronously.

3. Lock coarsening

If a series of successive operations are repeatedly locked and unlocked for the same object, even if the lock appears in the loop body, frequent mutex synchronization operations can lead to unnecessary performance loss even if there is no thread contention. If the virtual machine detects that a bunch of fragmented operations are locking the same object, the lock synchronization will be extended to the outside of the entire sequence of operations.

4. Lightweight lock

When the code enters the synchronization block, if the synchronization object is not locked, the virtual machine will first establish a space named lock record in the stack frame of the current thread to store the lock object's current copy of Mark Word, called displaced mark Word, Then, using the CAS action, try to update the object's mark Word to a pointer to the lock record, and if the update action succeeds, the thread has a lock on the object, and the object Mark Word's lock flag bit is converted to "00", which means it is in a lightweight lock state. If the update action fails, first check whether the object's mark word points to the current thread's stack frame, if so, you can go directly to the synchronization block to continue execution, otherwise the lock object is preempted by other threads, if there are more than two threads contention the same lock, then the lightweight lock is no longer valid, to expand into a heavyweight lock, The status value of the lock flag is changed to "10". The unlocking process is also done through CAS operations, and if the object's Mark Word still points to the thread's lock record, the CAS operation replaces the object's current mark Word and the copied displaced mark word in the thread, and if the replacement succeeds, the entire synchronization process is complete. If the substitution fails, indicating that another thread has attempted to acquire the lock, it is necessary to wake the suspended thread while releasing the lock.

Lightweight locks use CAS operations to avoid the overhead of using mutexes, and if there is lock contention, additional CAS operations occur in addition to the cost of mutexes.

5. Bias Lock

In the absence of competition to eliminate the entire synchronization, even the CAS operation is not done.

A biased lock will favor the first thread that acquires it, and if the lock is not fetched by another thread during the next execution, the thread holding the biased lock will never need to be synchronized.

Thread Safety and lock optimization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.