04 番外(待补充AQS相关原理) Java多线程中的各种锁

2019-08-13  本文已影响0人  攻城狮哦哦也

1 乐观锁 悲观锁

1.1 乐观锁

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。那么我们如何实现乐观锁呢,一般来说有以下2种方式:

1.2 悲观锁

2 内置锁 显式锁

2.1 内置锁

Synchronized 关键字结合对象的监视器,JVM 为我们提供了一种『内置锁』的语义,这种锁很简便,不需要我们关心加锁和释放锁的过程,我们只需要告诉虚拟机哪些代码块需要加锁即可,其他的细节会由编译器和虚拟机自己实现。

2.2 显式锁

Lock 显式锁
获取锁可以被中断,超时获取锁,尝试获取锁
Lock 接口位于 java.util.concurrent.locks 包下,基本定义如下:

public interface Lock {
    //获取锁,失败则阻塞
    void lock();
    //响应中断式获取锁
    void lockInterruptibly()
    //尝试一次获取锁,成功返回true,失败返回false,不会阻塞
    boolean tryLock();
    //定时尝试
    boolean tryLock(long time, TimeUnit unit)
    //释放锁
    void unlock();
    //创建一个条件队列
    Condition newCondition();
}

2.3 显式锁(Lock) 和 内置锁(synchronized)的比较

Synchronized

内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码就获得锁,走出相应的代码就释放锁。
通信
与Synchronized配套使用的通信方法通常有wait(),notify()。

Lock(一个实现类ReentrantLock)

ReentrantLock是显示锁,需要显示进行 lock 以及 unlock 操作。

通信
与ReentrantLock搭配的通行方式是Condition,如下:

private Lock lock = new ReentrantLock();  
private Condition condition = lock.newCondition(); 
condition.await();//this.wait();  
condition.signal();//this.notify();  
condition.signalAll();//this.notifyAll();

Condition是被绑定到Lock上的,必须使用lock.newCondition()才能创建一个Condition。从上面的代码可以看出,Synchronized能实现的通信方式,Condition都可以实现,功能类似的代码写在同一行中。而Condition的优秀之处在于它可以为多个线程间建立不同的Condition,比如对象的读/写Condition,队列的空/满Condition,在JDK源码中的ArrayBlockingQueue中就使用了这个特性:

public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}
public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}
private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    notEmpty.signal();
}
private E dequeue() {
    // assert lock.getHoldCount() == 1;
    // assert items[takeIndex] != null;
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

编码

Lock lock = new ReentrantLock();
lock.lock();
try{

}finally{
    lock.unlock();
}

相比于Synchronized要复杂一些,而且一定要记得在finally中释放锁而不是其他地方,这样才能保证即使出了异常也能释放锁。

灵活性

3 独占锁 共享锁

4 重入锁

可重入锁ReentrantLock
同一个线程可重复获取该锁,没获取一次加锁计数器加一

5 读写锁

概述

详细

6 公平锁 非公平锁

如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的,不满足,就是非公平的
非公平的效率一般来讲更高

7 死锁 活锁

7.1 死锁

7.2 活锁

上一篇 下一篇

猜你喜欢

热点阅读