LockSupport与AQS

LockSupport与AQS,第1张

LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语。

每个线程都会有一个独有的permit(许可)。

相比较于wait/notify/notifyAll有何优点?

注意:LockSupport是不可重入的:unpark三次之后,park一次可以继续运行,再次park还是会被阻塞。可以理解为unpark是把某个标志位标为1,并不是加1。park是将这个标志位标为0,而非减1。

AbstractQueuedSynchronizer,即队列同步器。它是构建锁或者其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),它是JUC并发包中的核心基础组件。

AQS简单地说就是使用一个FIFO的等待队列和一个volatile int state来实现同步的。即通过CAS state判断是否被锁(CAS来保证原子性、volatile保证可见性),将阻塞的线程打包放入等待队列中。

1 AQS的使用者一般定义一个内部类来继承AQS,使用组合的方式使用。

2 AQS有两种模式:排他和共享。

排他模式:只有一个线程可以拥有锁。(排他锁)

共享模式:可以同时多个线程拥有锁。(读锁)

AQS中两种模式下的waiting thread共用一个queue,所以一般使用者都只是使用一种模式。ReentrantReadWriteLock是同时使用了两种模式。

使用者继承AQS,实现AQS中的几个未实现的方法。然后就可以调用AQS的方法来实现自己的接口功能了。

我们可以看到ReentrantLock使用一个内部类Sync来继承AQS,然后实现排他锁的三个方法。

我们知道ReentrantLock有lock和unlock接口,可以看到这两个接口的实现就是调用AQS原有的方法。

前三个是排他锁所要实现的,后两个是共享锁所要实现了。注意:这五个函数并不是abstract,原因是因为一般都是使用某一种模式(排他或共享模式),所以子类只需使用其中一组就可以了。

在使用AQS的类中用来加锁和解锁的方法。

这里我们可以看到“获取锁,如果失败则加入队列”这个行为是由AQS来实现的。而如何判断失败?这个是由子类来决定的。这个决定支持了可重入性、是否公平性等功能。

共享模式下的对应的四个方法。

我们知道公平锁:先来的一定先获取锁。

非公平锁:当多个线程在争取锁,谁先获取锁的顺序是不固定的。

AQS的公平性是由使用者来决定的。

我们知道AQS中的acquire函数是大致这样实现的。

因为每次acquire的步骤是:先try再入队列。所以就可以出现这种情况:队列中有两个线程在等待,当锁被释放时,刚好又来了一个线程,则try的时候成功了,这样这个线程就获得锁了。

如果想要实现公平锁:tryAcquire的时候判断一下,如果有线程在等待,这个函数直接返回false。

显然非公平锁要比公平锁的效果要高。

问题一:加锁的意义不是锁住文件不让别人读写!!而是可以通过加锁这一 *** 作,来排斥多进程的。如:防止同一个程序同一时间运行多次!

问题二:要么有代码BUG,要么是文件确实发生了变化。(这个不太确定)

线程获取了写锁后,再去获取读锁,然后释放写锁,线程的锁就从写锁降级为了读锁

wlock();

try {

// 做写入 *** 作

} catch (Exception e) {

// process exception

}

rlock();

try {

wunlock();

// 任然持有读锁

} finally {

runlock();

}

以上就是关于LockSupport与AQS全部的内容,包括:LockSupport与AQS、读锁怎么用的、java reentrantreadwritelock 锁降级有什么用等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9503185.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存