directory

1. Synchronized keyword characteristics

Synchronized application: double check lock to achieve singleton mode

Explicit locking: Lock and ReentrantLock

1. Lock interface

2, already

4. Fairness of locks

Differences between synchronized and ReentrantLock

This article contains 2,303 words and 5,234 characters. It takes 6 minutes to read.

In Java, multi-threaded concurrent application scenarios, synchronization and security are particularly important in design, which is often mentioned in interviews. In a project, if you have experience with multithreading, locks are usually applied to Java to ensure thread safety and data consistency.

By now, the locking mechanism in Java is pretty comprehensive and powerful. There are many options for implementing synchronization, sharing, and mutual exclusion, including mechanisms for accessing shared objects: synchronized and volatile, and ReentrantLock mechanisms that provide advanced features.

This article simply records the principle and application of synchronized and ReentrantLock and the difference, in the future use of choice has a more clear basis.

1. Synchronized keyword characteristics

The sychronized keyword guarantees synchronization of access to resources between multiple threads; it modifies methods or blocks of code that can only be executed by one thread at a time.

Synchronized keyword is a mutual exclusion of native grammar level and implemented in JVM level. It is a heavyweight lock, because in the mutual exclusion state, the thread that has not acquired the lock will be suspended and blocked, and the operation of suspended thread and recovered thread needs to be completed in the kernel state.

In JDK1.6, synchronized was officially optimized in a large number of JVM levels, introducing spin lock, biased lock, adaptive spin lock, lock elimination, lock coarser, lightweight lock and other technologies to reduce the overhead of lock operation.

In addition, the above mentioned use of synchronized modifiers and code blocks, there are three main cases:

  1. Modifier instance method, used to lock the current object instance, before entering the synchronization code to obtain the current object instance lock.
  2. Modifies a static method that locks the current class object before entering the synchronized code.
  3. Modifies a code block to specify a lock object for a given object and obtains the lock for the given object before entering a synchronized code block.

Synchronized application: double check lock to achieve singleton mode

The singleton pattern implemented below is thread-safe and locks class objects using the synchronized keyword.

/** * Public class singleton {private static ** * public class singleton {private static ** * public class singleton {private static ** volatile singleton singletonInstance; Private singleton(){} public static singleton getSingletonInstance(){ Synchronized (singletonInstance==null){if (singletonInstance==null){synchronized (singletonInstance==null){ singletonInstance=new singleton(); } } } return singletonInstance; }}Copy the code

The volatile keyword is necessary because of the JVM’s instruction reordering nature, which can be 1->3->2.

In the case of multiple threads, the volatile keyword guarantees visibility and prevents the JVM from reordering instructions, ensuring that they will work even in multithreaded environments.

Explicit locking: Lock and ReentrantLock

1. Lock interface

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}
Copy the code

In JDK1.5, start to provide Lock interface, from the above source can be found, unlike synchronized internal locking mechanism, Lock provides unconditional, timed, polling, can interrupt Lock operations, Lock and unlock operations are explicit.

2, already

ReentrantLock is a mutex API provided in JDK1.5. It implements the Lock interface and provides the same mutual exclusion and memory visibility as synchronized.

ReentrantLock supports all Lock acquisition modes defined by the Lock interface, thus providing more flexibility in handling unavailable locks. The ReentrantLock mechanism is similar in nature to internal locking. Its advantages include:

  • The implementation of ReenTrantLock is a spinlock that is locked by cyclic calls to the CAS operation. It also performs better because it avoids the blocking that causes threads to enter the kernel state.
  • Simplified code, better integration with exception handling mechanisms, and in some cases, better performance.

Of course, when using ReentrantLock, you need to be aware of its features and problems.

As mentioned above, locking and unlocking are explicit operations, so this type of Lock is more complex than internal locking, and the Lock must be released in the finally block. In addition, if an exception is thrown outside the locked block, the lock will never be released. These problems are to be vigilant, error is difficult to find out the process of the point of occurrence.

class X { ReentrantLock lock = new ReentrantLock(); / /... public void m() { assert ! lock.isHeldByCurrentThread(); lock.lock(); try { // ... method body } finally { lock.unlock(); }}}Copy the code

4. Fairness of locks

The constructor of ReentrantLock provides a choice of two types of locks: non-fair locks (the default) and fair locks.

Part of the source code is as follows:

/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (! hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } /** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); } /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }Copy the code

A fair lock is to ensure that threads are requested in a first-come-first-served order. If the lock has been occupied by other threads or there are already threads waiting for the lock, the new thread will join the waiting queue. Non-fair locks allow preemption, in that the thread waits only when the lock is occupied, and does not cede the lock to another thread in the waiting queue once it is available.

In actual scenarios, the performance of unfair locks is significantly higher than that of fair locks.

As shown in the figure above, the ReentrantLock-based HashMap, ConcurrentHashMap, performed well in the tests, while the fair lock performed worst.

This is because:

In the case of fierce competition, preemption mechanism can make the thread obtain resources more efficiently. Applicable scenarios of unfair locks The period during which a lock is held or the average interval between lock requests is short.

Suppose thread A holds A lock, thread B requests the lock, and thread B is suspended until thread A releases the lock. At the same time, a thread C requests the lock, C has a chance to acquire the lock, and C may have released the lock before B wakes up. So, in this case, C gets the lock earlier and B gets the lock on wake up, which is an increase in throughput.

On the contrary, for a long lock holding time and a long average interval between lock requests, a fair lock is more advantageous.

Differences between synchronized and ReentrantLock

By now, we have preliminarily understood the principle and some application scenarios of synchronized keyword and ReentrantLock, and found their similarities and differences in the analysis process. Here is a brief summary:

  1. Both are reentrant locks.
  2. Synchronized is the keyword and belongs at the JVM level, while ReenTrantLock is the locking API.
  3. ReenTrantLock adds some advanced features over synchronized, as seen above.
  4. ReentrantLock implements selective locking.

Learning Java development, multithreading and other knowledge, recently I also follow this set of “Java engineers learning growth knowledge map” system learning, is the OFFICIAL launch of CSDN, the quality is very good!

Which contains the Java professional architecture complete details, recommended to everyone to learn to use, interested can scan code to view, recently I also in learning, of course, my article will record learning, welcome everyone to read, such as my column “Java treasure”, “Socket network programming”.

The expansion is like this, the size of 870mm*560mm typesetting is good, the content is very substantial. Recommended for those who need to learn Java!

If you feel good, welcome to “one button three even” oh, like collection attention, comments, questions and suggestions, welcome to exchange learning! Together refueling progress, we will see you next!

This content starting my CSDN blog: the force plan s3 】 【 csdn-czh.blog.csdn.net/article/det…