【搞定Java并发】 第五章 5.1 Java中的锁

目录

1、Lock接口

1.1 Lock的使用

1.2 Lock接口提供的synchronized关键字不具备的主要特性:尝试非阻塞地获取锁,能被中断地获取锁、超时获取锁

二、队列同步器AQS(AbstractQueuedSynchronizer(AQS))

三、可重入锁:ReentrantLock

四、读写锁:ReentrantReadWriteLock

五、LockSupport工具

5.1 LockSuppot源码


1、Lock接口

锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但有些锁可以允许多个线程并发访问共享资源,比如:读写锁)

在Lock接口出现之前,Java程序靠synchronized关键字实现锁功能。而Java SE5之后,并发包中新增了Lock接口用来实现锁功能,它提供了与synchronized关键字类似的同步功能。但在使用时需要显示的获取和释放锁。虽然他缺少了隐式获取和释放锁的便捷性,但却拥有了锁获取与释放的可操作性、可中断性及超时获取锁等synchronized关键字不具备的同步特性。

1.1 Lock的使用

Lock lock = new ReentrantLock();
lock.lock();
try{
    // ...
}finally{
    lock.unlock();
}


需要对Lock的使用进行两点说明:

1、在finally中释放锁:保证在获取锁之后,最终能够被释放;

2、不要将获取锁的过程写在try块中,因为如果在获取锁时发生了异常,异常抛出的同时,也会导致锁无故释放。

1.2 Lock接口提供的synchronized关键字不具备的主要特性:尝试非阻塞地获取锁,能被中断地获取锁、超时获取锁


Lock接口中的API


Lock接口的实现基本上都是通过聚合了一个同步器的子类来完成线程访问控制的。

看下Lock接口中的源码,实际上也就是上表中的这些API:


public interface Lock {
 
    // 获取锁    
    void lock();
 
    // 可中断的获取锁
    void lockInterruptibly() throws InterruptedException;
 
    // 尝试阻塞的获取锁
    boolean tryLock();
 
    // 超时获取锁
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
 
    // 释放锁
    void unlock();
 
    // 获取等待通知组件,该组件和当前锁绑定
    Condition newCondition();
}

二、队列同步器AQS(AbstractQueuedSynchronizer(AQS))

三、可重入锁:ReentrantLock

四、读写锁:ReentrantReadWriteLock

五、LockSupport工具

在AQS中,当需要阻塞或者唤醒一个线程的时候,都会使用LockSupport工具类来完成相应工作。LockSupport定义了一组公共的静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,而LockSupport也成为构建同步组件的基础工具。

LockSupport定义了一组以park开头的方法用来阻塞当前线程,以及unpark方法来唤醒一个被阻塞的线程。【是condition的wait和signal的基础】

在JDK6中,LockSupport增加了park(Object  blocker)、parkNanos(Object  blocker, long  nanos) 和 parkUntil(Object blocker, long deadline)3个方法,用于实现阻塞当前线程的功能,其中参数blocker是用来标识当前线程在等待的对象,该对象主要用于问题排查和系统监控,用于替代之前的park方法。

5.1 LockSuppot源码

        park方法:阻塞当前线程,先 setBlocker(t, blocker)保存一下将要阻塞的线程,然后调用本地方法unsafe.park(true, deadline)阻塞当前线程。只有当下面4种情况发生时,该方法才会返回。

  • 与park对应的unpark执行或已经执行时****
  • 线程被中断
  • 等待完成time参数制定的毫秒数时
  • 异常现象发生时,这个异常现象没有任何原因

package java.util.concurrent.locks;
import java.util.concurrent.*;
import sun.misc.Unsafe;
 
public class LockSupport {
    private LockSupport() {} 
 
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long parkBlockerOffset;
 
    static {
        try {
            parkBlockerOffset = unsafe.objectFieldOffset
                (java.lang.Thread.class.getDeclaredField("parkBlocker"));
        } catch (Exception ex) { throw new Error(ex); }
    }
 
    private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn't need a write barrier here.
        unsafe.putObject(t, parkBlockerOffset, arg);
    }
 
    // 唤醒处于阻塞状态的线程thread
    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);  //************
    }
 
    // 阻塞当前线程,blocker为当前线程在等待的对象
    public static void park(Object blocker) {  
        Thread t = Thread.currentThread();
        setBlocker(t, blocker); 
        unsafe.park(false, 0L); //************
        setBlocker(t, null);
    }
 
    // 阻塞当前线程,最长时间不超过nanos纳秒
    public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            unsafe.park(false, nanos);
            setBlocker(t, null);
        }
    }
 
    // 阻塞当前线程,直到deadline时间
    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(true, deadline);
        setBlocker(t, null);
    }
 
    // 获取当前线程的阻塞对象
    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return unsafe.getObjectVolatile(t, parkBlockerOffset);
    }
 
    // 阻塞当前线程
    public static void park() {
        unsafe.park(false, 0L);
    }
 
    // 阻塞当前线程,最长时间不超过nanos纳秒
    public static void parkNanos(long nanos) {
        if (nanos > 0)
            unsafe.park(false, nanos);
    }
 
    // 阻塞当前线程,直到deadline时间
    public static void parkUntil(long deadline) {
        unsafe.park(true, deadline);
    }
}

 

猜你喜欢

转载自blog.csdn.net/ZHAOJING1234567/article/details/89404787
今日推荐