《成长之路 -JAVA并发系列》 - (四)Lock体系

本文详细探讨了JAVA并发编程中的Lock体系,包括Lock与Synchronized的区别,AQS(AbstractQueuedSynchronizer)的工作原理及其如何维护锁状态和实现锁的获取,ReentrantLock的重入性和公平锁/非公平锁机制,以及Condition和CountDownLatch在多线程同步中的应用。
摘要由CSDN通过智能技术生成

Lock体系

1.lock与Synchronize比较:

(1)Synchronize是一个关键字,JAVA语言内置的特性;Lock是一个类,通过这个类实现同步访问。
(2)Synchronize不需要关心锁的获取与释放;lock需要手动获取释放锁,比较灵活。

2.AQS(AbstractQueuedSynchronizer):

(1)是什么?

AQS采用了模板方法设计模式,实现了同步状态的管理,线程排队等底层操作;具体的实现者只需要通过AQS提供的模板方法实现同步组件的语义即可。

(2)AQS如何维护锁状态?

定义了一个int类型的state,用volatile修饰保证内存可见性。1表示锁占用,0表示没被占用。另外采用CAS改变state状态保证线程安全。

(3)AQS如何实现锁的获取?

1.执行acquire方法,获取同步状态,即state。
2.获取成功执行线程逻辑。
3.获取失败,需要将线程加入同步队列。
4.同步队列为空则将线程节点入队。
5.不为空,CAS入队。
获取队列的线程:
1.当前节点是第一个吗?
2.不是则将节点状态设为SIGNAL,并将线程堵塞。
3.是第一个,尝试获取同步状态,成功将当前节点设为头结点,并执行线程逻辑。失败同2。
在这里插入图片描述

(4)如何使用?
class Sync extends AbstractQueuedSynchronizer {
public boolean tryAcquire(int acquires) {
	if (compareAndSetState(0, 1)) {
		setExclusiveOwnerThread(Thread.currentThread());
		return true;
	}
	return false;
}

继承AQS重写tryAcquire方法,用CAS改变状态,成功代表获取了锁。

3.ReentrantLock:

实现了Lock接口,有个内部类继承了AQS。支持重入性,还支持公平锁和非公平锁两种方式。

(1)重入性:

当一个线程获取锁后再次获取该锁不会堵塞。ReentrantLock通过对同步状态计数的方式实现重入性。即线程获取锁state加1,释放锁减1。当state为0时才使完全释放锁。

(2)公平锁和非公平锁:

公平与不公平是相对于锁而言的:
公平锁是线程请求锁后,如果同步队列为空则尝试加锁,不为空要将线程加入到同步队列中。
非公平锁是线程请求锁后,不管同步队列是否为空都会尝试加锁。
公平锁保证请求资源时间上的绝对顺序,这就需要频繁的上下文切换;而非公平锁降低一定的上下文切换,保证系统更大的吞吐量,不过非公平锁可以会导致有些线程很久获取不到锁。

4.Condition机制:

Object的wait和notify/notify是与对象监视器配合完成线程间的等待/通知机制,而Condition与Lock配合完成等待通知机制,前者是java底层级别的,后者是语言级别的,具有更高的可控制性和扩展性。
在这里插入图片描述

Condition实现了一个等待队列,它是一个单向队列。当调用await方法时会将线程加入到等待队列,并将锁释放;调用signal或者signalAll时会将线程从等待队列移动到AQS定义的同步队列里。

5.CountDownLatch:

join操作可以实现两个线程间的同步关系,如果有很多线程需要同步,比如A,B,C执行完后才执行D,这样join就没办法实现。所以引入了CountDownLatch,它也是内部类继承了AQS。源码如下:

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    Sync(int count) {
        setState(count);
    }

    int getCount() {
        return getState();
    }

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    protected boolean tryReleaseShared(int releases) {
        // Decrement count; signal when transition to zero
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}

初始化时将state设为count,获取锁时只有state为0。调用countDown()方法相当于释放锁。所以我们知道当state不为0时会将线程加入到同步队列,通过countDown()减少state的值,当state为0时同步队列中的线程开始执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值