In-depth understanding of Java in the lock (B)

locks package structure level

img

Lock Interface

The method of signature description
void lock(); Acquire the lock (die endlessly)
boolean tryLock(); To obtain a lock (tasted)
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; Acquire the lock (date not wait)
void lockInterruptibly() throws InterruptedException; Acquire the lock (mercy)
void unlock(); Release the lock
Condition newCondition();  

Code Example:

public class GetLockDemo {

  // 公平锁
  // static Lock lock =new ReentrantLock(true);

  // 非公平锁
  static Lock lock = new ReentrantLock();

  public static void main(String[] args) throws InterruptedException {
    // 主线程 拿到锁
    lock.lock();

    Thread thread =
        new Thread(
            () -> {
              // 子线程 获取锁(不死不休)
              System.out.println("begain to get lock...");
              lock.lock();
              System.out.println("succeed to get lock...");

              //              // 子线程 获取锁(浅尝辄止)
              //              boolean result = lock.tryLock();
              //              System.out.println("是否获得到锁:" + result);
              //
              //              // 子线程 获取锁(过时不候)
              //              try {
              //                boolean result1 = lock.tryLock(5, TimeUnit.SECONDS);
              //                System.out.println("是否获得到锁:" + result1);
              //              } catch (InterruptedException e) {
              //                e.printStackTrace();
              //              }
              //
              //              // 子线程 获取锁(任人摆布)
              //              try {
              //                System.out.println("start to get lock Interruptibly");
              //                lock.lockInterruptibly();
              //              } catch (InterruptedException e) {
              //                e.printStackTrace();
              //                System.out.println("dad asked me to stop...");
              //              }

            });

    thread.start();
    Thread.sleep(10000L);
    lock.unlock();
  }
}

in conclusion:

  • lock () the most common
  • lockInterruptibly in () method is generally more costly, and some classes may not be implemented to achieve lockInterruptible () method. Interrupted only when really needed, use only, before using the implementation class should see the description of the method.

Condition

Object of wait (), notify (), notifyAll () method is used and synchronized with one or more threads may wake up. Lock Condition is used in conjunction with the need to provide a plurality of sets and waiting for more precise control (bottom layer is a park / unpark mechanism);

Collaboration Deadlock Embodiment 1 (locked) Deadlock Mode 2 (first waking up and then hangs) Remark
suspend/resume Deadlock Deadlock Deprecated
wait/notify No deadlock Deadlock Only for the synchronized keyword
park/unpark Deadlock No deadlock  
condition No deadlock Deadlock  

condition code example:

public class ConditionDemo {

  static Lock lock = new ReentrantLock();

  static Condition condition = lock.newCondition();

  public static void main(String[] args) throws InterruptedException {
    Thread thread =
        new Thread(
            () -> {
              lock.lock();
              System.out.println("condition.await()");
              try {
                condition.await();
                System.out.println("here i am...");
              } catch (InterruptedException e) {
                e.printStackTrace();
              } finally {
                lock.unlock();
              }
            });
    thread.start();

    Thread.sleep(2000L);
    lock.lock();

    condition.signalAll();

    lock.unlock();
  }
}

ReetrantLock

ReentrantLock is reentrant lock, the same thread can acquire the lock multiple times

img

The principle analysis ReentrantLock

  1. ReentrantLock need an owner that is used to mark a thread to acquire a lock, a count for the number of records locked and no list of thread lock to grab a waiters waiting queue is used to store
  2. When a thread come in, it will first determine the value of count, if the count is 0 showing that the lock is not occupied
  3. Then grab the lock operation by CAS
  4. If you add a lock to grab the value of the count, but the owner set a reference to the current thread
  5. If the count is not 0 at the same time owner points to the current thread's reference value will count plus 1
  6. If the count is not zero while the owner is not a reference point to the current thread, the thread will be placed in the waiting queue waiters
  7. If the CAS grab the lock fails, the thread into the wait in the queue waiters
  8. When the thread is finished using the lock, the lock will release its holdings, the value will count minus 1 releases the lock, if the count is 0 then the owner is set to null
  9. If the count value is not the head of the queue waiting thread will grab a lock Wake 0

Manually implement ReentrantLock Code Example:

public class MyReentrantLock implements Lock {

  // 标记重入次数的count值
  private AtomicInteger count = new AtomicInteger(0);

  // 锁的拥有者
  private AtomicReference<Thread> owner = new AtomicReference<>();

  // 等待队列
  private LinkedBlockingDeque<Thread> waiters = new LinkedBlockingDeque<>();

  @Override
  public boolean tryLock() {
    // 判断count是否为0,若count!=0,说明锁被占用
    int ct = count.get();
    if (ct != 0) {
      // 判断锁是否被当前线程占用,若被当前线程占用,做重入操作,count+=1
      if (owner.get() == Thread.currentThread()) {
        count.set(ct + 1);
        return true;
      } else {
        // 若不是当前线程占用,互斥,抢锁失败,return false
        return false;
      }
    } else {
      // 若count=0, 说明锁未被占用,通过CAS(0,1) 来抢锁
      if (count.compareAndSet(ct, ct + 1)) {
        // 若抢锁成功,设置owner为当前线程的引用
        owner.set(Thread.currentThread());
        return true;
      } else {
        return false;
      }
    }
  }

  @Override
  public void lock() {
    // 尝试抢锁
    if (!tryLock()) {
      // 如果失败,进入等待队列
      waiters.offer(Thread.currentThread());

      // 自旋
      for (; ; ) {
        // 判断是否是队列头部,如果是
        Thread head = waiters.peek();
        if (head == Thread.currentThread()) {
          // 再次尝试抢锁
          if (!tryLock()) {
            // 若抢锁失败,挂起线程,继续等待
            LockSupport.park();
          } else {
            // 若成功,就出队列
            waiters.poll();
            return;
          }
        } else {
          // 如果不是队列头部,就挂起线程
          LockSupport.park();
        }
      }
    }
  }

  public boolean tryUnlock() {
    // 判断,是否是当前线程占有锁,若不是,抛异常
    if (owner.get() != Thread.currentThread()) {
      throw new IllegalMonitorStateException();
    } else {
      // 如果是,就将count-1  若count变为0 ,则解锁成功
      int ct = count.get();
      int nextc = ct - 1;
      count.set(nextc);
      // 判断count值是否为0
      if (nextc == 0) {
        owner.compareAndSet(Thread.currentThread(), null);
        return true;
      } else {
        return false;
      }
    }
  }

  @Override
  public void unlock() {
    // 尝试释放锁
    if (tryUnlock()) {
      // 获取队列头部, 如果不为null则将其唤醒
      Thread thread = waiters.peek();
      if (thread != null) {
        LockSupport.unpark(thread);
      }
    }
  }

  @Override
  public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    return false;
  }

  @Override
  public void lockInterruptibly() throws InterruptedException {}

  @Override
  public Condition newCondition() {
    return null;
  }
}

synchronized VS Lock

synchronized

advantage:

  • Simple to use, semantic clarity, where the point where the need
  • Provided by the JVM, it provides a variety of optimization (coarsening lock, the lock cancellation biased locking, lightweight lock)
  • Release the lock is done by the virtual machine without manual intervention, reducing the possibility of deadlock

Cons: pessimistic exclusive lock, the lock can not be achieved advanced features such as fair locks, read-write locks, etc.

Lock

Advantages: can achieve synchronized lock can not be achieved advanced features such as fair locks, read-write locks, etc., but also can realize more functions 

Disadvantages: need to manually release the lock unlock, improper use is likely to cause deadlock

 

Conclusion: Both are reentrant lock, synchronized can be analogized to fool the camera, provides a fixed function, and can be compared to unilateral Lock can be adjusted according to the desired function

 

 

Guess you like

Origin www.cnblogs.com/coding-diary/p/11247039.html