Java Reentrantlock Analysis

Source: Internet
Author: User


Often used in concurrent programming is this Reentrantlock class, where threads acquire locks and release locks. There is also a synchronized, commonly used to control the acquisition of multi-threaded lock mechanism.


Let's write a simple example.

package com.multi.thread;import java.util.concurrent.locks.lock;import  Java.util.concurrent.locks.reentrantlock;public class aqsdemo {public static void  main (String[] args)  {lock lock = new reentrantlock (true); Mythread t1 = new mythread ("T1",  lock); Mythread t2 = new mythread ("T2",  lock); Mythread t3 = new mythread ("T3",  lock); T1.start (); T2.start (); T3.start ();}} Class mythread extends thread {private lock lock;public mythread (String  name, lock lock)  {super (name); this.lock = lock;} @Overridepublic  void run ()  {lock.lock (); Try {system.out.println (Thread.CurrentThread ()  +  "  is running "); Try {thread.sleep (500);}  catch  (interruptedexception e)  {e.printstacktrace ();}}  finally {lock.unlock ();}}}


This is a simple code that uses Reentrantlock.


Knowledge Point Understanding:

Reentranctlock:

1) Reentrant: The general meaning is that if a function can be executed safely and repeatedly, then the function can be duplicated. It sounds very round-mouth.

2) can be re-entered lock: A thread can repeatedly get the lock it already owns.


Characteristics:

1) Reentrantlock can be used in a variety of ways.

2) Support the concept of fair lock and non-fair lock

Static final class Nonfairsync extends Sync; (non-fair lock)

Static final class Fairsync extends Sync; (Fair lock)

3) Support interrupt lock, receive interrupt signal can release its own lock.

4) Support time-out acquisition Lock: The Trylock method is to attempt to acquire a lock, which is supported by a timing limit, waiting for a certain amount of time to return.


Reentrantlock first briefly Aqs (Abstractqueuedsynchronizer). Java.util.concurrent package Many classes are based on AQS as the basis for development, condition,blockingqueue and thread pool use of workers are based on the implementation, in fact, the cumbersome concurrent process of negative clutter package up, So that other development tools are easier to develop. It is mainly through the volatile and unsafe class atomic operation, to achieve blocking and synchronization.


Aqs is an abstract class in which other classes acquire locks primarily by overloading their tryacquire (int arg), and tryrelease to release locks.

Aqs not here to do analysis, there will be a separate article to learn Aqs.


There are three classes in the Reentrantlock class, Sync,nonfairsync,fairsync these three classes,Nonfairsync and Fairsync classes inherit from the Sync class, The sync class inherits from the Abstractqueuedsynchronizer abstract class.


Sync is the main implementation of Reentrantlock for fair and unfair locking, and Reentrantlock is a non-fair lock by default.

Lock lock = new Reentrantlock (true); : True is a fair lock, False is a non-fair lock, nothing is a non-fair lock default.


Non-fair Lock:

Lock.lock (); Enter the code into the Reentranctlock internal class sync.

    abstract static class sync  extends abstractqueuedsynchronizer {        private  static final long serialversionuid = -5179523762034025860l;         /**         * performs {@link  Lock#lock}. The main reason for subclassing          * is to allow fast path for nonfair version.          */        abstract  void lock ();                  Omitted.       } 

This abstract class of sync has an abstract method, lock (), which is supplied to the Nonfairsync,fairsync two implementation classes. This is a template method design pattern, the specific logic to provide sub-class to achieve.

The lock method of the non-fair lock, although you can see for yourself, but still paste out, say a bit.

 static final class NonfairSync extends Sync {         private static final long serialVersionUID =  7316153563782823691l;        /**          * performs lock.  try immediate barge, backing up  to normal         * acquire on failure.          */        final  void lock ()  {            if  ( Compareandsetstate (0, 1))                  setexclusiveownerthread (Thread.CurrentThread ());             else&nBsp;               acquire (1);         }         Omit     }

In fact, the focus of this compareandsetstate (0,1), this is actually an atomic operation, is the CAS operation to get the resources of the thread. It is represented by setting it to 1 if the original value is 0 and returning true. In fact, this code is setPrivate volatile intState;

The principle is to get the memory address of State directly through unsafe and then manipulate the memory directly. If the setting succeeds, it means that the lock has been acquired and if it fails, it will enter:

Public final void acquire (int arg) {if (!tryacquire (ARG) && acquirequeued (Addwaiter (node.exclus    IVE), Arg) selfinterrupt (); }

In this method, the process is to determine whether the state of the lock is available, if the lock is held, then determine whether the thread holding the lock is not the current thread, if it is the lock holding increment, this is the Java layer implementation of the principle of reentrant. If it fails again, it enters the waiting queue. is to go in and wait for the queue. Aqs has an internal class that node is used to store the thread information for the lock.


The AQS thread blocking queue is a two-way queue that provides the FIFO feature, the head node represents the header, and the tail represents the tail.

1) node nodes, maintain a volatile state, maintain a prev point forward a queue node, based on the state of the previous node to determine whether to acquire the lock.

2) When the current thread is released, it only needs to modify its state, and subsequent nodes will observe the volatile state and change the acquisition lock. Volatile is placed in memory, shared, so the previous node changes state, and subsequent nodes see this status information.


When the lock fails, it is added to the queue, but one thing, the unfair lock is that each new thread gets the resulting time, not directly to the tail of the queue, but also to the CAs to modify state status to see if the lock succeeds.


Summary of Unfair locks:

First will try to change the state of the AQS, the change succeeds to acquire the lock, otherwise after the failure again by judging whether the state is 0, if it is 0, try to acquire the lock again. If the state is not 0, the lock has already been held by other threads, but other threads may also be themselves, so be sure to decide whether to get the thread yourself, if it is a success, and the number of locks is 1, which is a reentrant lock, not a node blocking queue. After joining the queue, you decide whether to block it by judging the current thread state in the for loop. It can be seen that before joining the queue and before blocking multiple attempts to acquire the lock, and avoid entering the thread block, this is because the blocking, wakeup requires CPU scheduling, and context switching, this is a heavyweight operation, should try to avoid .


Fair Lock:

Fairsync class: Final void lock ()  {   //first to determine the state of the lock, rather than go directly to get acquire (1);} Aqs class: Public final void acquire (Int arg)  {    if  (!tryacquire (ARG)  &&        acquirequeued (AddWaiter (Node.EXCLUSIVE),  arg))         selfinterrupt ();} Fairsync class: Protected final boolean tryacquire (Int acquires)  {     Final thread current = thread.currentthread ();     int c =  getstate ();    if  (c == 0)  {         //hasqueuedpredecessors determine if there is a previous node, if there is no attempt to get the lock         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;}


Fair lock, the main difference is: Everything must have a first served, first come first. The lock is acquired by looking at whether the lock is available and whether there are any nodes, that is, whether there is a blocking queue. If it is, it is placed directly at the end of the queue instead of acquiring a lock.


Release Lock:

Public void unlock ()  {sync.release (1);} Public final boolean release (Int arg)  {    if  (Tryrelease ( ARG))  {        Node h = head;         if  (h != null && h.waitstatus != 0)             unparksuccessor (h);         return true;    }    return  false;} 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;}


The release of the lock is very simple, is to change the state of the value, after the change if the state is 0, then the release succeeds, if the direct can be re-entered several times, but also to release many times the lock.


Release process:

The head node is the thread node that currently holds the lock, and when the lock is released, the next point of the head node, if it is not null, and the waitstatus is not greater than 0, skips judgment, otherwise the first Waitstatus node is found forward from the end of the queue. The node thread is then awakened through Locksupport.unpark (S.thread). It can be seen that Reentrantlock's unfair lock is not fair when acquiring a lock, and if it enters the waiting queue, the thread unlock () in the head node will wake up in the order of entry, guaranteeing the FIFO characteristics of the queue.


Reference article:

http://silencedut.com/2017/01/09/%E7%94%B1ReentrantLock%E5%88%86%E6%9E%90JUC%E7%9A%84%E6%A0%B8%E5%BF%83AQS/


Http://www.cnblogs.com/leesf456/p/5383609.html


Https://github.com/pzxwhc/MineKnowContainer/issues/16

This article is from the "10093778" blog, please be sure to keep this source http://10103778.blog.51cto.com/10093778/1930644

Java   Reentrantlock   Analytics

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.