java常用锁

java常用锁类型

常见的锁大致可以分为:乐观锁,悲观锁,排他锁,共享锁,分段锁,自选锁,公平锁,非公平锁等。。今天来学基于CAS非加锁实现的乐观锁

ReentrantLock锁

ReentrantLock类是一种可重入,公平/非公平,独占锁,它于synchronized具有相同的功能和语义,但是它更强大,它支持中断,超时等操作。Sync是ReentrantLock的内部类,他的两个子类分别代表公平锁和非公平锁,ReentrantLock可以在构造方法选择是否公平。

    public void lock() {
        sync.lock();
    }
     public void unlock() {
        sync.release(1);
    }

lock和unlock都是基于内部类Sync实现的,因此我们了解的重点是Sync

内部类Sync

Sync是ReentrantLock定义的一个静态内部类,他继承了AbstractQueuedSynchronizer类。它有两个实现类分别为NonfairSync(非公平锁),FairSync(公平锁),

非公平锁lock方法
        final void lock() {
            if (compareAndSetState(0, 1))//尝试获得锁
                setExclusiveOwnerThread(Thread.currentThread());
            else
            	  调用AQS的acquire(int arg)方法
                acquire(1);
        }
公平锁lock方法
        final void lock() {
            acquire(1);//直接调用AQS的acquire(int arg)方法
        }

其实无论是公平或者非公平锁的lock方法最重要的就是tryAcquire(int acquires)方法

非公平锁tryAcquire(int acquires)方法
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
        
        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;
        }
公平锁tryAcquire(int acquires)方法
 protected final boolean tryAcquire(int acquires) {
 		  //公平锁相对于非公平锁就是多了hasQueuedPredecessors()来实现公平策略
            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;
        }
    }
hasQueuedPredecessors()
    public final boolean hasQueuedPredecessors() {

        Node t = tail;//获得尾部节点
        Node h = head;//获得前继节点
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

首先头部节点不等于尾部节点则代表队列不为空--------->true
s为空则代表有头节点----------->true
s不为空且s的线程不等于当前线程--------->true

demo
public class TestReentrantLock {
    private static volatile ReentrantLock lock=new ReentrantLock();
    public static void main(String[] args) {
        new Thread(()->{
            lock.lock();
            System.out.println("线程一先工作呢");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程一下班啦");
            lock.unlock();
        }).start();
        new Thread(()->{
            lock.lock();
            System.out.println("线程二在工作呢");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程二下班啦");

            lock.unlock();
        }).start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMJ2UeYq-1592028252772)(/images/pasted-16.png)]

Semaphore信号量

Semaphore是一种公平/非公平锁,共享锁。它可以做为一个计数器,用来保护一个或多个锁。跟上面讲解的ReentrantLock独占锁一样,核心代码都是基于类中定义的静态内部类Sync。

acquire()方法
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//可以被中断的获锁方法
    }

从信号量获取一个许可,如果无可用许可前将一直阻塞等待。

acquireSharedInterruptibly(int arg)方法
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())//如果当前线程被中断就抛出异常
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//尝试获得异常
            doAcquireSharedInterruptibly(arg);//获锁失败放进等待队列
    }
tryAcquireShared(int arg)方法
非公平锁实现
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
        
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();//获得可用锁数量
                int remaining = available - acquires;
                //如果没有锁了就直接返回否则尝试获得锁资源
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
公平锁实现
protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())//公平策略就是判断当前节点是否有前驱节点(跟上面的ReentrantLock的公平策略一样的)
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
doAcquireSharedInterruptibly(int arg)

分析请见

release(int arg)方法
    public void release() {
        sync.releaseShared(1);
    }

释放信号量中的一个许可,如果多次调用会扩大信号量的可用数量。

releaseShared(int arg)方法
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg))//尝试释放锁 {
            doReleaseShared();
            return true;
        }
        return false;
    }
tryReleaseShared(int releases)方法
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();//获得队列中可用锁数量
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))//尝试设置数量
                    return true;
            }
        }
doReleaseShared()方法

分析请见

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值