Java concurrency family directory

  • 1. The low-level implementation of Java concurrency mechanism
  • 2. Atomic manipulation classes in Java
  • [Java Concurrency series] 3. Locks in Java

Discusses the classes under LOCKS (including interfaces) in the J.U.C package

A lock is used to control the access of multiple threads to a shared resource. Usually, a lock prevents multiple threads from accessing a shared resource at the same time (except the read/write lock, which allows multiple read locks to read the shared resource at the same time).

1. The Lock interface

The Lock interface provides synchronization functions similar to the synchronized keyword. However, when using Lock, you need to explicitly obtain the Lock. Compared with synchronized, Lock loses the convenience of acquiring locks implicitly, but can control the acquisition and release of locks, and can interrupt locks and timeout locks.

2. Main API of Lock interface

  • void lock(); Acquiring a lock
  • void lockInterruptibly(); Interruptible lock acquisition, which differs from the lock() method in that the current thread is interrupted when lockInterruptibly is used to acquire the lock;
  • boolean tryLock(); Try a non-blocking lock acquisition. When this method is called, it returns true if it can be acquired or false if it cannot.
  • boolean tryLock(long time, TimeUnit unit); Timeout acquisition lock
  • void unlock(); Release the lock
  • Condition newCondition(); The wait() method of this component can be called only if the current thread has acquired the lock. After calling wait(), the current thread releases the lock.

3. Lock interface implementation class

1. ReentrantLock

A reentrant lock is a reentrant lock that allows a thread to repeatedly lock a resource.

Reentry: Any thread that acquires a lock can acquire it again without blocking. Fair and Unfair lock acquisition: Fair means that in absolute time, the thread that requests the lock first (the thread with the longest waiting time is the first to acquire the lock), then the lock is fair, otherwise, it is unfair.

①. Re-entry of the lock

If lock re-entry is to be implemented, two problems are ready to be solved:

  • Lock acquisition:To acquire the lock, the lock needs to check whether the thread that acquired the lock has already acquired the lock (that is, whether the current thread owns the lock), if so, then the lock was acquired successfully; The following code is an unfair way to acquire locks

    “`java

    final boolean nonfairTryAcquire(int acquires) {
    Final Thread current = thread.currentThread (); Int c = getState();if(c == 0) {// No threadif (compareAndSetState(0, acquires)) {
                  setExclusiveOwnerThread(current);
                  return true; }} // Check whether the thread is currently holding the lockelse if(current == getExclusiveOwnerThread()) {int nexTC = c + acquires;if (nextc < 0) // overflow
                  throw new Error("Maximum lock count exceeded");
              setState(nextc);
              return true;
          }
          return false;
      }Copy the code
In this method, first determine whether the lock has been occupied, if not, use CAS to set the synchronization status. If the lock has been occupied, it will determine whether the current thread is the thread that owns the lock, and then determine whether the acquisition operation is successful. If the thread that acquired the lock requests to acquire the lock again, the synchronization status value will be increased and returnedtrue. So the reentrant lock is acquired when the thread reentrant success, increase the lock synchronization status value. - ** lock release: ** thread repeats N times to acquire the lock, then it must release N times before other threads can acquire the lock. Java protected Final Boolean tryRelease(int releases) {int c = getState() -releases;if(Thread.currentThread() ! = getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free =false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }Copy the code

If a lock is acquired N times by a thread, the first (n-1) lock will return false, and when the synchronization state is completed and released (c=0), the owning thread will be set to NULL and the lock will return true.

②. Fair and unfair lock acquisition

Here is the code for fair lock acquisition:

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; }}Copy the code

In this code, only the hasqueuedToraise () method, which determines whether the current node in the synchronous queue has a precursor node (that is, a thread that acquired the lock earlier than the current thread), is added to the if condition, compared to the code above that acquired the lock unfairly. So when hasqueued24 () returns true, it waits for the precursor thread to acquire and release the lock before it can resume acquiring it.

2. ReadWriteLock

Exclusive lock: Only one thread is allowed to access the read/write lock at the same time. Multiple reader threads are allowed to access the read/write lock at the same time. When the writer thread accesses the read thread and other writer threads are blocked. Read/write locks maintain a read lock and a write lock, with read/write separation to improve concurrent performance (at least better than exclusive locking performance).

// Todo read/write lock has more content, which will be written later

4. LockSupport class

The LockSupport class, which is included in the J.U.C. Hooks package, defines common static methods that provide basic thread blocking and wake up functionality. The following table shows some methods and descriptions provided in LockSupport:

methods describe
public static void park() Blocks the current thread and returns from the park() method when another thread calls unpark() or interrupts the current thread
fipublic static void parkNanos(long nanos) Blocks the current thread and returns automatically after nanos nanoseconds
public static void parkUntil(long deadline) Blocks the current thread until the deadline
public static void unpark(Thread thread) Wake up a blocked thread