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 锁降级有什么用等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)