当前位置:网站首页>AQS learning

AQS learning

2022-04-23 20:05:00 Fairy wants carry

Catalog

summary :

Protection methods that need to be implemented by subclasses

  Other methods

Difference between lock and synchronizer  

Custom Lock - An exclusive lock

AQS Summary


summary :

Inherit it to realize the function of the parent class

Get the lock :

Blocking and obtaining resources is park and unpark;

Release the lock :

Determine whether there are lock resources :

  

 AbstractQueuedSynchronizer Public methods (AQS)

1.acquire: Get sync state exclusively ;

2.release: Exclusive release synchronization state ;

3.acquireShared(int arg):

Shared get synchronization status , If the current thread does not get the synchronization state , Then go into the queue and wait ——> The main difference from exclusive mode is that multiple threads can obtain synchronization status at the same time ;

4.releaseShared(int arg): Shared release synchronization state ;

Protection methods that need to be implemented by subclasses

 1.tryAcquire: Get sync state exclusively ;—— adopt cas Operate to set the lock resource occupancy status , And for the lock Owner Set it up

 2.tryRelease: Exclusive release synchronization state ;

 3.getState: Return to lock state

There are several more. shared

  Other methods

Difference between lock and synchronizer  

lock : For users , Defines how locks interact with users  , Hidden the details ;

synchronizer : For lock implementers , Simplifies the implementation of locks ;

The lock and synchronizer well isolate the user from the areas that need to be concerned by the implementation ;


Custom Lock - An exclusive lock

package com.example.juc.AQS;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import static java.lang.Thread.sleep;

/**
 * @author diao 2022/4/23
 */
@Slf4j(topic = "c.TestAqs")
public class TestAqs {
    public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(()->{
           lock.lock();
           log.debug("locking...");
           lock.lock();//synchronized and ReentrantLock Are reentrant 
            try {
                log.debug("locking...");
                sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        },"t1").start();

//      new Thread(()->{
//          lock.lock();
//          try {
//              log.debug("locking...");
//          } finally {
//              log.debug("unlocking...");
//              lock.unlock();
//          }
//      },"t2").start();
    }
}

// Custom Lock ( Do not reenter the lock ); Reentrant lock : You can enter the lock resource the next time you enter 
class MyLock implements Lock{

    // An exclusive lock ,AQS Based on queues ( synchronizer )
    class MySync extends AbstractQueuedSynchronizer{

        /*1. Try to get lock resources */
      @Override
        protected boolean tryAcquire(int arg) {
            // Because there may be multiple threads competing for lock resources , So go ahead with cas
            if(compareAndSetState(0,1)){
                // Try to lock the owner Set as current thread 
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /*2. Try to release the lock resource */
        @Override
        protected boolean tryRelease(int arg) {
            // Here we need to pay attention to the order ,setState Yes volatile Field 
            //  There is a read-write barrier , The previous modification lock has resources that are visible to other threads 
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /*3. Determine whether to hold an exclusive lock */
        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }

        public Condition newCondition(){
            return new ConditionObject();
        }
    }

    private MySync sync=new MySync();

    @Override// Lock ( You don't succeed , Will enter the waiting queue )
    public void lock() {
        sync.acquire(1);
    }

    @Override// Lock , Can interrupt 
    public void lockInterruptibly() throws InterruptedException {
         sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override// Try to lock , With timeout 
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,unit.toNanos(time));
    }

    @Override// Unlock 
    public void unlock() {
        /**
         *  and sync Medium tryRelease It's different 
         *  The above is just to change the owner of the lock and the of the lock state, Threads are not blocked but will not wake up 
         * release Wakes up blocked threads 
         */
        sync.release(1);
    }

    @Override// Returns the condition variable 
    public Condition newCondition() {
        return sync.newCondition();
    }
}

  As the code shows , Exclusive lock realizes that only one thread can obtain the lock at the same time , Other threads that acquire locks can only wait in the waiting queue ;


AQS Summary

  Usage mode ?

AQS Mainly through inheritance , Subclasses inherit the synchronizer and implement its abstract methods -> To manage synchronization status ;

How to manage synchronization status ?

AQS Use one int A member variable of type state To indicate the synchronization state , When state>0 Indicates that the lock has been acquired , When state = 0 When the lock is released . It offers three ways (getState()、setState(int newState)、compareAndSetState(int expect,int update)) To synchronize state state To operate , Of course AQS Make sure you are right state The operation of is safe .

characteristic :

AQS adopt Built in FIFO Synchronize the queue to complete the queuing of resource acquisition thread , If the current thread fails to get the synchronization status ,AQS The current thread and wait status will be constructed into a node (Node) And add it to the synchronization queue , At the same time, it will block the current thread ;

Stand at the angle of use , I understand that there are only two functions : Exclusive and shared , Either exclusive or shared , Then call the bottom api;

AQS The general realization of

AQS One was maintained internally CLH Queue to manage locks . The thread will first try to acquire the lock , If it fails, it will wrap the current thread and wait status information into a node Nodes join the synchronization queue sync queue in . And then it's going to loop around trying to get the lock ( The spin ), The condition is that the current node is head The immediate successor will try . If you fail, you will block yourself until you are awakened . When the thread holding the lock releases the lock , Will wake up subsequent threads in the queue .

CLH(Craig,Landin,and Hagersten) queue Is a virtual two-way queue ( Virtual two-way queue means there is no queue instance , There is only an association between nodes ).AQS It is to encapsulate each thread requesting shared resources into a CLH A node in a lock queue (Node) To achieve lock allocation .
 

版权声明
本文为[Fairy wants carry]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231947061595.html