Re-learning Multithreading (iii)--lock

Source: Internet
Author: User
Tags prev volatile
Objective

Locks are used to control how multiple threads access a shared resource. Before the lock interface appears, the Java program relies on the Synchronized keyword to implement the lock function, although lock is more explicitly acquired and released when used, but it has the operability of lock acquisition and release, An interruptible acquisition lock and a timeout to acquire the synchronization characteristics of a variety of synchronized keywords that are not available in the lock. Lock's API interface

Lock is an interface, interface, interface. Important thing to say three times. Public
interface Lock {
    //Get lock
    void Lock ();

    interruptible access to lock
    void lockinterruptibly () throws interruptedexception;

    Try non-blocking fetch lock, immediately return
    Boolean trylock ();

    Timeout gets
    The lock Boolean trylock (long time, Timeunit unit) throws interruptedexception;

    Release lock
    void Unlock ();

    Gets the wait notification component
    Condition newcondition ();
}
Internal implementation of lock AQS queue Synchronizer Introduction

The Aqs (abstractqueuedsynchronizer) queue Synchronizer is the underlying framework for building locks or other synchronization components. The synchronization state is generally managed by inheriting the Synchronizer and implementing its abstract methods. The Synchronizer provides 3 methods (GetState (), setstate (int newstate) and compareandsetstate (int expect, int update) to change the synchronization state.
Synchronizer is the key to achieve the lock, the lock in the implementation process of aggregation Synchronizer, the use of Synchronizer to achieve the semantics of the lock.

The Synchronizer provides the following overridable methods:

protected Boolean tryacquire (int var1) {
        throw new unsupportedoperationexception ();
    }

    protected Boolean tryrelease (int var1) {
        throw new unsupportedoperationexception ();
    }

    protected int tryacquireshared (int var1) {
        throw new unsupportedoperationexception ();
    }

    protected Boolean tryreleaseshared (int var1) {
        throw new unsupportedoperationexception ();
    }

    Protected Boolean isheldexclusively () {
        throw new unsupportedoperationexception ();
    }
AQS Queue Synchronizer Implementation synchronization queue

The Synchronizer relies on internal synchronization queues to complete the synchronization state management, and the queue node data structure is as follows:

Static Final class Node {static final Abstractqueuedsynchronizer.node SHARED = new Abstractqueuedsynchronizer.nod
        E ();
        Static final Abstractqueuedsynchronizer.node EXCLUSIVE = null;
        static final int cancelled = 1;
        static final int SIGNAL =-1;
        static final int CONDITION =-2;
        static final int PROPAGATE =-3;
        volatile int waitstatus;
        Volatile Abstractqueuedsynchronizer.node prev;
        Volatile Abstractqueuedsynchronizer.node next;
        volatile thread thread;

        Abstractqueuedsynchronizer.node Nextwaiter;
        Final Boolean isshared () {return this.nextwaiter = = SHARED; Final Abstractqueuedsynchronizer.node predecessor () throws NullPointerException {Abstractqueuedsyn Chronizer.
            Node var1 = This.prev;
            if (var1 = = null) {throw new NullPointerException ();
            else {return var1; } Node ({} Node (Thread var1, Abstractqueuedsynchronizer.node var2) {this.nextwaiter = var2;
        This.thread = var1;
            Node (Thread var1, int var2) {this.waitstatus = var2;
        This.thread = var1; }
    }

From the above code, the synchronous queue is a FIFO bidirectional queue. Exclusive Synchronization State acquisition

Public final void acquire (int var1) {
        if!this.tryacquire (var1) && this.acquirequeued (This.addwaiter ( AbstractQueuedSynchronizer.Node.EXCLUSIVE), var1)) {
            selfinterrupt ();
        }
    }
Private node Addwaiter (node mode) {
        node node = new Node (Thread.CurrentThread (), mode);
        Node pred = tail;
        if (pred!= null) {
            Node.prev = pred;
            if (Compareandsettail (pred, node)) {
                pred.next = node;
                return node;
            }
        }
        Enq (node);
        return node;
    }
Private Node Enq (final node node) {for
        (;;) {
            Node t = tail;
            if (t = = null) {//Must initialize
                if (Compareandsethead (new Node ()))
                    tail = head;
            } else {
                Node.prev = t ;
                if (Compareandsettail (t, node)) {
                    t.next = node;
                    return t;}}}
    

When the thread calls the acquire (int) method, the specific process is as follows:
Shared Synchronization State Acquisition

Public final void acquireshared (int arg) {
        if (tryacquireshared (ARG) < 0)
            doacquireshared (ARG);
    }
private void doacquireshared (int arg) {
        final node node = addwaiter (node.shared);
        Boolean failed = true;
        try {
            Boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor ();
                if (p = = head) {
                    int r = tryacquireshared (ARG);
                    if (r >= 0) {
                        setheadandpropagate (node, r);
                        P.next = null; Help GC
                        if (interrupted)
                            selfinterrupt ();
                        Failed = false;
                        return;
                    }
                if (Shouldparkafterfailedacquire (p, node) &&
                    parkandcheckinterrupt ())
                    interrupted = true;
            }
        Finally {
            if (failed)
                cancelacquire (node);
        }
    
Exclusive timeout get sync status
Private Boolean Doacquirenanos (int arg, long nanostimeout) throws Interruptedexception {if (nanostime
        Out <= 0L) return false;
        Final long deadline = System.nanotime () + nanostimeout;
        Final node node = addwaiter (node.exclusive);
        Boolean failed = true; try {for (;;)
                {final Node P = node.predecessor ();
                    if (p = = head && tryacquire (ARG)) {Sethead (node); P.next = null;
                    Help GC failed = false;
                return true;
                } nanostimeout = Deadline-system.nanotime ();
                if (nanostimeout <= 0L) return false;
                    if (Shouldparkafterfailedacquire (p, node) && nanostimeout > Spinfortimeoutthreshold)
                Locksupport.parknanos (this, nanostimeout); if (thread.interrupted ())
                    throw new Interruptedexception ();
        Finally {if (failed) cancelacquire (node); }
    }

The specific process is as follows:
Common lock Reentrantlock

Reentrantlock, re-lock, can support a thread to lock the resource repeatedly. This lock supports the fairness and unfairness of the selection when acquiring a lock.

Final Boolean nonfairtryacquire (int acquires) {
            final Thread current = Thread.CurrentThread ();
            int c = getState ();
            if (c = = 0) {
                if (compareandsetstate (0, acquires)) {
                    setexclusiveownerthread (current);
                    return true;
                }
            else if (current = = Getexclusiveownerthread ()) {
                int nextc = c + acquires;
                if (NEXTC < 0)//overflow
                    throw new Error ("Maximum lock count Exceeded");
                SetState (NEXTC);
                return true;
            }
            return false;
        }
 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; }
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 only difference between fair and unfair locks is the hasqueuedpredecessors () method, that is, whether the current node in the synchronization queue has a precursor node.

The fair lock guarantees the acquisition of the lock according to the FIFO principle, while the cost is carried out by a large number of thread switches; The unfair lock may cause the thread to "starve", but the very few threads switch, guaranteed the greater throughput. Reentrantreadwritelock

Reentrantreadwritelock can be read-write lock, the Readwritelock interface is realized, and the Readlock () method and Writelock () method are used to acquire the reading lock and write lock. Read and write State design

Read-write locks need to maintain the state of multiple threads and a write thread in the sync state. The read-write lock divides the variable into two parts, a high 16-bit read, and a low 16-bit representation write. Assuming that the current read-write state is S, the write state equals S&0X0000FFFFF, and the read state equals s>>>16. The write state adds 1 o'clock, equals s+1, reads the state to increase 1 o'clock, equals s+ (1<<16). Write lock Fetch

A write lock is an exclusive lock that supports reentrant entry. If the current thread has acquired a write lock, the write state is added, and the current thread enters the wait state if the read lock has been fetched or the thread that acquired the write lock is not the current thread.

Protected Final Boolean tryacquire (int acquires) {
            Thread current = Thread.CurrentThread ();
            int c = getState ();
            int w = Exclusivecount (c);
            if (c!= 0) {
                //(Note:if C!= 0 and w = 0 then shared count!= 0)
                if (w = = 0 | | current!= GETEXCLUSIVEOWNERTHR EAD ()) return
                    false;
                if (W + exclusivecount (acquires) > Max_count)
                    throw new Error ("Maximum lock COUNT exceeded");
                Reentrant acquire
                SetState (c + acquires);
                return true;
            }
            if (Writershouldblock () | |
                ! Compareandsetstate (c, C + acquires)) return
                false;
            Setexclusiveownerthread (current);
            return true;
        }
Read lock Fetch

The

Read lock is a shared lock that supports reentrant, and read locks are always successfully fetched when no other write thread is accessed, and the read status is increased if the current thread has acquired a read lock. When the current thread acquires a read lock, the write lock is acquired by another thread, and it enters the wait state.

Protected Final Boolean tryreleaseshared (int unused) {Thread current = Thread.CurrentThread ();
                if (Firstreader = = current) {//Assert firstreaderholdcount > 0;
                if (Firstreaderholdcount = = 1) Firstreader = null;
            else firstreaderholdcount--;
                else {holdcounter RH = Cachedholdcounter;
                if (RH = NULL | | | Rh.tid!= getthreadid (current)) RH = Readholds.get ();
                int count = Rh.count;
                    if (count <= 1) {readholds.remove ();
                if (count <= 0) throw unmatchedunlockexception ();
            }--rh.count; for (;;)
                {int c = getState ();
                int NEXTC = C-shared_unit; if (Compareandsetstate (c, NEXTC)) return NEXTC = =0; }
        }
Lock demotion

Lock demotion is the process of holding the current write lock, acquiring the read lock, and then releasing the write lock. The emphasis is on acquiring the reading lock, keeping the writing lock in the process of acquiring the reading lock, and ensuring the visibility of the data. Condition interface

The condition interface provides an object-like monitor method that can be used in conjunction with lock to implement a wait/notify mode.

Public interface Condition {
    //equal to object's Wait () method
    void await () throws interruptedexception;

    void awaituninterruptibly ();

    Long Awaitnanos (long nanostimeout) throws interruptedexception;

    A wait (long timeout) method equivalent to object is a
    Boolean await (long time, timeunit) throws interruptedexception;

    Boolean awaituntil (Date deadline) throws Interruptedexception;

    The Notify () method equivalent to object is
    void signal ();

    The Notifyall () method equivalent to object is
    void Signalall ();
}
Summarize

In general, the lock object can replace the Synchronized keyword, which is the advanced level of the Synchronized keyword. Mastering lock helps to learn and contract the principle of the source code, in order to be in the actual development of fluency.

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.