1.公平锁/非公平锁
1.1 公平锁概述
公平是针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序。
ReentrantLock、ReadWriteLock默认都是非公平模式,非公平锁的效率高于公平锁(不浪费的线程切换).
1.2 自写公平锁
FairLock,QueueObject
import java.util.ArrayList;
import java.util.List;
//该类去掉了可重入的功能.
//https://gitee.com/zgy/codes/7seiqx2nwuo4dhrj8pf6m33这里有公平锁代码
public class FairLock {
private boolean isLocked = false;
private Thread lockingThread = null;
//对列来记录调用lock的顺序
private List<QueueObject> waitingThreads = new ArrayList<QueueObject>();
//每来一个线程调用lock就记录产生一个QueueObject,然后保存到队列中.
//this是调用lock的线程自己.
public void lock() throws InterruptedException {
QueueObject queueObject = new QueueObject();
synchronized (this) {
waitingThreads.add(queueObject);
}
try {
queueObject.doWait();
} catch (InterruptedException e) {
synchronized (this) {
waitingThreads.remove(queueObject);
}
throw e;
}
}
//线程调用unlock的时候,取队列中的第一个donotify
public synchronized void unlock() {
if (this.lockingThread != Thread.currentThread()) {
throw new IllegalMonitorStateException("Calling thread has not locked this lock");
}
isLocked = false;
lockingThread = null;
if (waitingThreads.size() > 0) {
waitingThreads.get(0).doNotify();
}
}
}
public class QueueObject {
//是否叫醒.
private boolean isNotified = false;
public synchronized void doWait() throws InterruptedException {
//死循环,如果没有叫醒就一直等待
while (!isNotified) {
this.wait();
}
this.isNotified = false;
}
public synchronized void doNotify() {
this.isNotified = true;
this.notify();
}
public boolean equals(Object o) {
return this == o;
}
}
复制代码
1.3 ReentrantLock中的公平锁和非公平锁
ReentrantLock.FairSync ReentrantLock.FairSync
package java.util.concurrent.locks;
public class ReentrantLock implements Lock, java.io.Serializable {
//1.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
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;
}
}
//2.FairSync
static final class FairSync extends Sync {
//公平的tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//和非公平的区别是有这句话,也就是没有前驱的情况下,也就是自己是第一个的时候才返回true.
//如果有前置则返回false,等待前置的线程被获取到cpu
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;
}
}
//3. NonfairSync
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
}
复制代码
1.4 ReentrantReadWriteLock 也有公平锁和非公平锁.
package java.util.concurrent.locks;
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
abstract static class Sync extends AbstractQueuedSynchronizer {
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
}
}
复制代码
2.排它锁和共享锁
2.1 概述
- 排它锁 排它锁,也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。(原子性,排斥其它线程进入. )
- 共享锁 共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。(可以有多个线程同时访问)
2.2 举例
- ReentrantLock就是一种排它锁。CountDownLatch是一种共享锁。这两类都是单纯的一类,即,要么是排它锁,要么是共享锁。
- ReentrantReadWriteLock是同时包含排它锁和共享锁特性的一种锁,这里主要以ReentrantReadWriteLock为例来进行分析学习。我们使用ReentrantReadWriteLock的写锁时,使用的便是排它锁的特性;使用ReentrantReadWriteLock的读锁时,使用的便是共享锁的特性。
3.读写锁
3.1 读写锁概述
同时包含排它锁和共享锁,写锁是排它锁,读锁是共享锁.
- 读读:可以多线程进入,保证读的性能提高,线程不互斥等待
- 读写:线程互斥等待,只要是写的时候不能进行其它操作,多个读可以同时进行.
- 写写:线程互斥等待 ReentrantReadWriteLock用的也有公平锁和非公平锁.
3.2 示例
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyReadWriteLock {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
private Lock r = rwl.readLock();
private Lock w = rwl.writeLock();
public Object get(String key) {
r.lock();
System.out.println(Thread.currentThread().getName() + " 读操作在执行..");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
} finally {
r.unlock();
System.out.println(Thread.currentThread().getName() + " 读操执行完毕..");
}
}
public void put(String key, Object value) {
w.lock();
System.out.println(Thread.currentThread().getName() + " 写操作在执行..");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
} finally {
w.unlock();
System.out.println(Thread.currentThread().getName() + " 写操作执行完毕..");
}
}
}
ublic class MyReadWriteLockTest {
public static void main(String[] args) {
writeWrite();
writeRead();
readRead();
}
//多个写,一个结束后再下一个
/**
Thread-0 写操作在执行..
Thread-0 写操作执行完毕..
Thread-2 写操作在执行..
Thread-2 写操作执行完毕..
Thread-1 写操作在执行..
Thread-1 写操作执行完毕..
*/
public static void writeWrite() {
MyReadWriteLock myReadWriteLock1 = new MyReadWriteLock();
new Thread(new Runnable() {
@Override
public void run() {
myReadWriteLock1.put("key1", "value1");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
myReadWriteLock1.put("key2", "value2");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
myReadWriteLock1.put("key3", "value3");
}
}).start();
}
/**
* main 写操作在执行..
main 写操作执行完毕..
Thread-0 读操作在执行..
Thread-0 读操执行完毕..
Thread-2 写操作在执行..
Thread-0->value1
Thread-2 写操作执行完毕..
Thread-1 读操作在执行..
Thread-3 读操作在执行..
Thread-3 读操执行完毕..
Thread-1 读操执行完毕..
Thread-1->value2
Thread-3->value2
*/
//写和读,写的时候不能读,多个读的时候可以同时进行
public static void writeRead() {
MyReadWriteLock myReadWriteLock2 = new MyReadWriteLock();
myReadWriteLock2.put("key1", "value1");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
myReadWriteLock2.put("key1", "value2");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1"));
}
}).start();
}
//读读的时候,多个读可以同时进行
public static void readRead() {
MyReadWriteLock myReadWriteLock3 = new MyReadWriteLock();
myReadWriteLock3.put("key1", "value1");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock3.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(myReadWriteLock3.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(myReadWriteLock3.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(myReadWriteLock3.get("key1"));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(myReadWriteLock3.get("key1"));
}
}).start();
}
}
复制代码
4.ReentrantReadWriteLock源码解析
4.1 概述
- 读写锁需要保存的状态
-
- 写锁重入的次数
-
- 读锁的个数
-
- 每个读锁重入的次数
1111 1111 1111 1111-1111 1111 1111 1111
- 前16位(高位)保存读锁个数,后16位(低位)保存写锁个数 int值就表示重入的次数
4.2 核心源码
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
//1.私有readerLock和writerLock,通过下面的writeLock()和readLock()来访问
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
//1.1 构造方法
public ReentrantReadWriteLock() {
this(false);
}
//1.1.1 调用内部类ReadLock和WriteLock,此时创建了sync
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
//通过该public方法来访问writeLock和readerLock
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
//2.ReadLock内部类,sync是外部的sync,是构造ReadLock的时候传进来的.
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
//2.1 用的是外部内中的同步器sync
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
//2.2 读锁调调的是共享锁
public void lock() {
sync.acquireShared(1);
}
}
//3.WriteLock内部类,sync是外部的sync,是构造WriteLock的时候传进来的.
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
//3.1 写锁调的是非共享锁
public void lock() {
sync.acquire(1);
}
}
//Sync内部类实现类AQS
abstract static class Sync extends AbstractQueuedSynchronizer {
/*
SHARED_SHIFT->16
SHARED_UNIT->65536
MAX_COUNT->65535
EXCLUSIVE_MASK->65535
int最大值为:-2147483648到2147483648(有符号),
int无符号0~4,294,967,296(2^32),拆分为2部分最大值为65536(2^16)(65536*65536=4,294,967,296)
1111 1111 1111 1111-1111 1111 1111 1111
高位读锁,低位写锁,前16位保存读锁个数(65536),后16位保存写锁个数(65536)
*/
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count */
//拿到共享锁,读锁的个数,3个无符号右移()
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
//独占锁,写锁的个数,
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
//获取独占锁
protected final boolean tryAcquire(int acquires) {}
//释放独占锁
protected final boolean tryRelease(int releases) {}
//获取共享锁,这里面要先判断是否读锁,然后是否本线程,然后是其它线程,
//还保存了每个读锁的次数及总次数
protected final int tryAcquireShared(int unused) {}
//释放共享锁
protected final boolean tryReleaseShared(int unused) {}
}
//FairSync内部类
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
//NonfairSync内部类
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
}
}
复制代码
4.3 核心总结:
- 1.有WriteLock和ReadLock,都用的是Sync同步器,Sync 继承AbstractQueuedSynchronizer,也有公平和不公平
- 2.WriteLock写锁调用的是Sync的排他锁tryAcquire,ReadLock调用的是Sync的共享锁tryAcquireShared,都记录了重入的次数
- 3.private volatile int state;state的前16位(高位)保存读锁重入次数(65536),后16位(低位)保存写锁重入次数(65536)
- 4.有内部类调用外部类的属性的操作.
5. ReentrantReadWriteLock锁降级
5.1 概述
-
锁降级是指写锁降级为读锁。锁降级指的是写锁降级成为读锁。锁降级是指把持住当前拥有的写锁的同时,再获取到读锁,随后释放写锁的过程
-
锁升级 ReentrantReadWriteLock不支持锁升级 把读锁升级为写锁,在读锁没有释放的时候,获取到写锁,再释放读锁
5.2 官方示例
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
复制代码
代码中声明了一个volatile类型的cacheValid变量,保证其可见性。首先获取读锁,如果cache不可用,则释放读锁,获取写锁,在更改数据之前,再检查一次cacheValid的值,然后修改数据,将cacheValid置为true,然后在释放写锁前获取读锁;此时,cache中数据可用,处理cache中数据,最后释放读锁。这个过程就是一个完整的锁降级的过程,目的是保证数据可见性,如果当前的线程C在修改完cache中的数据后,没有获取读锁而是直接释放了写锁,那么假设此时另一个线程T获取了写锁并修改了数据,那么C线程无法感知到数据已被修改,则数据出现错误。如果遵循锁降级的步骤,线程C在释放写锁之前获取读锁,那么线程T在获取写锁时将被阻塞,直到线程C完成数据处理过程,释放读锁。
5.3 运用举例
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteDegrade {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
private Lock r = rwl.readLock();
private Lock w = rwl.writeLock();
private volatile boolean isUpdate;
//又有读操作又有写操作的例子
public void readWrite() {
r.lock(); // 为了保证isUpdate能够拿到最新的值
if (isUpdate) {
r.unlock();
w.lock();
map.put("xxx", "xxx");
r.lock();
w.unlock();
}
Object obj = map.get("xxx");
System.out.println(obj);
r.unlock();
}
public Object get(String key) {
r.lock();
System.out.println(Thread.currentThread().getName() + " 读操作在执行..");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
} finally {
r.unlock();
System.out.println(Thread.currentThread().getName() + " 读操执行完毕..");
}
}
public void put(String key, Object value) {
w.lock();
System.out.println(Thread.currentThread().getName() + " 写操作在执行..");
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
} finally {
w.unlock();
System.out.println(Thread.currentThread().getName() + " 写操作执行完毕..");
}
}
}
复制代码
参考文章: 读写锁ReentrantReadWriteLock之锁降级
6. StampedLock(JDK8以后)
6.1 概述
StampedLock是ReentrantReadWriteLock升级.
/stæmpt/
6.1.1 ReentrantReadWriteLock的缺点
- 读写锁(ReentrantReadWriteLock)是互斥的-读写互斥,写写互斥.读读不互斥.
- 由于读比较多,可能造成写线程饥饿(抢占不到资源),
- ReentrantReadWriteLock可以用的公平锁. 但是公平锁相对非公平锁性能低.
- StampedLock 提高读写互斥的性能,读锁并不会阻塞写锁,同时还提升性能.
6.1.2 StampedLock优点原理
实现类读锁并不会阻塞写锁,那怎么保证读写的一致性呢?--如果在读的时候发生写锁,则重新读. 怎么知道 读的时候正好发生了锁呢?- 有一个票据.如果乐观锁就读写不互斥. 如果拿到的是悲观锁则读写互斥.
6.2 官方示例
lass Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
//下面看看乐观读锁案例
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead(); //获得一个乐观读锁
double currentX = x, currentY = y; //将两个字段读入本地局部变量
if (!sl.validate(stamp)) { //检查发出乐观读锁后同时是否有其他写锁发生?
stamp = sl.readLock(); //如果没有,我们再次获得一个读悲观锁
try {
currentX = x; // 将两个字段读入本地局部变量
currentY = y; // 将两个字段读入本地局部变量
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
//下面是悲观读锁案例
void moveIfAtOrigin(double newX, double newY) { // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock();
try {
while (x == 0.0 && y == 0.0) { //循环,检查当前状态是否符合
long ws = sl.tryConvertToWriteLock(stamp); //将读锁转为写锁
if (ws != 0L) { //这是确认转为写锁是否成功
stamp = ws; //如果成功 替换票据
x = newX; //进行状态改变
y = newY; //进行状态改变
break;
}
else { //如果不能成功转换为写锁
sl.unlockRead(stamp); //我们显式释放读锁
stamp = sl.writeLock(); //显式直接进行写锁 然后再通过循环再试
}
}
} finally {
sl.unlock(stamp); //释放读锁或写锁
}
}
}
复制代码
6.3 代码示例
import java.util.concurrent.locks.StampedLock;
public class StampedLockThread {
private int balance; //余额
private StampedLock lock = new StampedLock();
//带条件的读写的问题
public void conditionReadWrite(int value) {
// 首先判断balance的值是否符合更新的条件,余额只能为正数.
long stamp = lock.readLock();//获取票据
try{
//多次循环执行(随便写的一个条件)
while (balance > 0) {
long writeStamp = lock.tryConvertToWriteLock(stamp);//读锁,如果条件成立可以转换为写锁.
if (writeStamp != 0) { // 成功转换成为写锁
stamp = writeStamp;
balance += value;
break;
} else {
// 没有转换成写锁,这里需要首先释放读锁,然后再拿到写锁
lock.unlockRead(stamp);
// 获取写锁
stamp = lock.writeLock();//更新票据
}
}
}finally {
lock.unlock(stamp);//锁都释放掉
}
}
//乐观锁读
public void optimisticRead() {
long stamp = lock.tryOptimisticRead();
try {
int c = balance;
// 这里可能会出现了写操作,因此要进行判断,如果发生了有写操作,需要重新读数据.
if (!lock.validate(stamp)) {
// 要从新读取
long readStamp = lock.readLock();
c = balance;
stamp = readStamp;
}
///
}
finally {
lock.unlockRead(stamp);
}
}
//读-获取乐观锁
public void read2() {
long stamp = lock.readLock();
try {
lock.tryOptimisticRead(); //获取乐观锁
int c = balance;
System.out.print("read2-stamp:" + stamp + ",balance:" + balance);
// ...
}finally {
lock.unlockRead(stamp);
}
}
//读-和ReentrantReadWriteLock一样
public void read() {
long stamp = lock.readLock();
try {
int c = balance;
System.out.print("read-stamp:"+stamp+",balance:"+balance);
// ...
}finally {
lock.unlockRead(stamp);
}
}
//写-和ReentrantReadWriteLock一样
public void write(int value) {
long stamp = lock.writeLock(); //写锁,有返回值,
try {
System.out.print("write-stamp:"+stamp+",value:"+value);
balance += value;
System.out.println(",balance:"+balance);
}finally {
lock.unlockWrite(stamp); //解锁
}
}
}
复制代码
6.4 核心源码
package java.util.concurrent.locks;
public class StampedLock implements java.io.Serializable {
/**
* Exclusively acquires the lock, blocking if necessary
* until available.
*
* @return a stamp that can be used to unlock or convert mode
*/
//拿到写锁才返回,票据就是返回值即注释中说的stamp
public long writeLock() {
long s, next; // bypass acquireWrite in fully unlocked case only
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : acquireWrite(false, 0L));
}
/**
* Exclusively acquires the lock if it is immediately available.
*
* @return a stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
//立刻返回,票据就是返回值即注释中说的stamp ,拿不到就返回0
public long tryWriteLock() {
long s, next;
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : 0L);
}
/**
* Non-exclusively acquires the lock, blocking if necessary
* until available.
*
* @return a stamp that can be used to unlock or convert mode
*/
//非独占锁
public long readLock() {
long s = state, next; // bypass acquireRead on common uncontended case
return ((whead == wtail && (s & ABITS) < RFULL &&
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L));
}
/**
* Non-exclusively acquires the lock if it is immediately available.
*
* @return a stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
//非独占锁,立刻返回,,票据就是返回值即注释中说的stamp ,拿不到就返回0
public long tryReadLock() {
for (;;) {
long s, m, next;
if ((m = (s = state) & ABITS) == WBIT)
return 0L;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
}
/**
* Returns a stamp that can later be validated, or zero
* if exclusively locked.
*
* @return a stamp, or zero if exclusively locked
*/
//获取乐观的读锁
public long tryOptimisticRead() {
long s;
return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
}
/**
* Returns true if the lock has not been exclusively acquired
* since issuance of the given stamp. Always returns false if the
* stamp is zero. Always returns true if the stamp represents a
* currently held lock. Invoking this method with a value not
* obtained from {@link #tryOptimisticRead} or a locking method
* for this lock has no defined effect or result.
*
* @param stamp a stamp
* @return {@code true} if the lock has not been exclusively acquired
* since issuance of the given stamp; else false
*/
//根据票据的值来返回是否修改过
public boolean validate(long stamp) {
U.loadFence();
return (stamp & SBITS) == (state & SBITS);
}
//释放写锁
public void unlockWrite(long stamp) {
WNode h;
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
if ((h = whead) != null && h.status != 0)
release(h);
}
//释放读锁
public void unlockRead(long stamp) {
long s, m; WNode h;
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS) ||
(stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
throw new IllegalMonitorStateException();
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
}
}
//释放读锁或写锁
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L)
break;
else if (m == WBIT) {
if (a != m)
break;
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return;
}
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return;
}
throw new IllegalMonitorStateException();
}
//转换为读锁
public long tryConvertToReadLock(long stamp) {
}
//转换为写锁
public long tryConvertToWriteLock(long stamp) {
}
}
复制代码
7.ReentrantReadWriteLock,StampedLock,synchronized对比总结
- StampedLock要比ReentrantReadWriteLock更加廉价,也就是消耗比较小。
- synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定;
- ReentrantLock、ReentrantReadWriteLock,、StampedLock都是对象层面的锁定,要保证锁定一定会被释放,就必须将unLock()放到finally{}中;
- StampedLock 对吞吐量有巨大的改进,特别是在读线程越来越多的场景下;
- StampedLock有一个复杂的API,对于加锁操作,很容易误用其他方法;
- 当只有少量竞争者的时候,synchronized是一个很好的通用的锁实现;
- 当线程增长能够预估,ReentrantLock是一个很好的通用的锁实现;
- StampedLock 可以说是Lock的一个很好的补充,吞吐量以及性能上的提升足以打动很多人了,但并不是说要替代之前Lock的东西,毕竟他还是有些应用场景的,起码API比StampedLock容易入手,