重入锁:
- 同一时刻只能有一条线程拥有重入锁,但此线程可以重复获得锁。
- 其余需求获得此锁的线程被阻塞。
- 代码实现关键是记录当前获得锁的线程。
public class ReentranceLock {
//记录当前获得锁的线程。
private Thread lockedBy = null;
private boolean isLocked = false;
private int lockCount = 0;
public synchronized void lock() throws InterruptedException {
Thread callingThread = Thread.currentThread();
while (isLocked && lockedBy != callingThread) {
wait();
}
isLocked = true;
lockedBy = callingThread;
lockCount++;
}
public synchronized void unlock() {
if (Thread.currentThread() == lockedBy) {
lockCount--;
if (lockCount == 0) {
isLocked = false;
notify();
}
}
}
}
读/写锁:
1.线程获得读锁条件
- 没有其他线程已获得写锁,并且没有其他线程需求写锁(Read Access)
- 此线程已获得读锁(Read Reentrance)
- 此线程已获得写锁(Write to Read Reentrance)
2.线程获得写锁条件
- 没有其他线程已获得写锁,或者写锁(Write Access)
- 此线程已获得写锁(Write Reentrance)
- 此线程已获得读锁,且为唯一一个线程获得读锁(Read to Write Reentrance)
public class ReadWriteLock {
//多个线程课同时获得读锁,用map记录线程以及对应线程获取锁次数
private Map<Thread, Integer> readingThreads = new HashMap<>();
//同一时刻,仅有一个线程可以获得写锁
private Thread writingThread = null;
//获得写锁的线程获得锁的次数
private int writers = 0;
//需求写锁的线程数
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException {
Thread callingThread = Thread.currentThread();
while(!canGrantReadAccess(callingThread)){
wait();
}
readingThreads.put(callingThread,
(getAccessCount(callingThread) + 1));
}
public synchronized void unlockRead() {
Thread callingThread = Thread.currentThread();
//当前线程没有获得读锁,抛出异常
if (!isReader(callingThread)) {
throw new IllegalMonitorStateException(
"Calling Thread does not" + " hold a read lock on this ReadWriteLock");
}
int accessCount = getAccessCount(callingThread);
if (accessCount == 1) {
readingThreads.remove(callingThread);
} else {
readingThreads.put(callingThread, (accessCount - 1));
}
notifyAll();
}
//此线程是否可以获得读锁
private boolean canGrantReadAccess(Thread callingThread){
if(isWriter(callingThread)) return true;
if(writers > 0) return false;
if(isReader(callingThread)) return true;
if(writeRequests > 0) return false;
return true;
}
//此线程是否已经获得读锁
private boolean isReader(Thread callingThread){
return readingThreads.get(callingThread) != null;
}
//此线程是否已经获得读锁的次数
private int getAccessCount(Thread callingThread){
Integer accessCount = readingThreads.get(callingThread);
if( accessCount == null) return 0;
return accessCount.intValue();
}
public synchronized void lockWrite() throws InterruptedException {
writeRequests++;
Thread callingThread = Thread.currentThread();
while(! canGrantWriteAccess(callingThread)){
wait();
}
writeRequests--;
writers++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException {
if(!isWriter(Thread.currentThread())){
throw new IllegalMonitorStateException("Calling Thread does not" +
" hold the write lock on this ReadWriteLock");
}
writers--;
if (writers == 0) {
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread){
if(isOnlyReader(callingThread)) return true;
if(hasReaders()) return false;
if(writingThread == null) return true;
if(!isWriter(callingThread)) return false;
return true;
}
private boolean hasReaders() {
return readingThreads.size() > 0;
}
private boolean isWriter(Thread callingThread) {
return writingThread == callingThread;
}
private boolean isOnlyReader(Thread callingThread){
return readingThreads.size() == 1 &&
readingThreads.get(callingThread) != null;
}
}
参考:
Java Concurrency / Multithreading Tutorial