马道蓉,第七子降魔之战西瓜影音,钟摆型眼球震颤
在java并发包java.util.concurrent中,除了重入锁reentrantlock外,读写锁reentrantreadwritelock也很常用。在实际开发场景中,在使用共享资源时,可能读操作远远多于写操作。这种情况下,如果对这部分共享资源能够让多个线程读的时候不受阻塞,仅仅在写的时候保证安全性,这样效率会得到显著提升。读写锁reentrantreadwritelock便适用于这种场景。
再描述一下进入读锁和写锁的条件。
进入读锁:
1.没有其他线程的写锁
2.有写请求且请求线程就是持有锁的线程
进入写锁:
1.没有其他线程读锁
2.没有其他线程写锁
本篇从源码方面,简要分析reentrantreadwritelock的实现原理,以及展示一下它的使用效果。
源码
这是reentrantreadwritelock维护的一对锁
/** inner class providing readlock */ private final reentrantreadwritelock.readlock readerlock; /** inner class providing writelock */ private final reentrantreadwritelock.writelock writerlock;
reentrantreadwritelock的构造器中,同时实例化读写锁,同时与reentrantlock相同,也有公平锁和非公平锁之分
public reentrantreadwritelock(boolean fair) { sync = fair ? new fairsync() : new nonfairsync(); readerlock = new readlock(this); writerlock = new writelock(this); }
写锁
获取锁
public void lock() { sync.acquire(1); } //这里与reentrantlock相同 public final void acquire(int arg) { if (!tryacquire(arg) && acquirequeued(addwaiter(node.exclusive), arg)) selfinterrupt(); } protected final boolean tryacquire(int acquires) { thread current = thread.currentthread(); int c = getstate(); int w = exclusivecount(c); if (c != 0) { // (note: if c != 0 and w == 0 then shared count != 0) if (w == 0 || current != getexclusiveownerthread()) return false; if (w + exclusivecount(acquires) > max_count) throw new error("maximum lock count exceeded"); // reentrant acquire setstate(c + acquires); return true; } if (writershouldblock() || !compareandsetstate(c, c + acquires)) return false; setexclusiveownerthread(current); return true; }
这里解析tryacquire()方法。
释放锁
public void unlock() { sync.release(1); } public final boolean release(int arg) { if (tryrelease(arg)) { node h = head; if (h != null && h.waitstatus != 0) unparksuccessor(h); return true; } return false; } protected final boolean tryrelease(int releases) { if (!isheldexclusively()) throw new illegalmonitorstateexception(); int nextc = getstate() - releases; boolean free = exclusivecount(nextc) == 0; if (free) setexclusiveownerthread(null); setstate(nextc); return free; }
分析tryrelease()方法
读锁
获取锁
public void lock() { sync.acquireshared(1); } public final void acquireshared(int arg) { if (tryacquireshared(arg) < 0) doacquireshared(arg); } protected final int tryacquireshared(int unused) { thread current = thread.currentthread(); int c = getstate(); if (exclusivecount(c) != 0 && getexclusiveownerthread() != current) return -1; int r = sharedcount(c); if (!readershouldblock() && r < max_count && compareandsetstate(c, c + shared_unit)) { if (r == 0) { firstreader = current; firstreaderholdcount = 1; } else if (firstreader == current) { firstreaderholdcount++; } else { holdcounter rh = cachedholdcounter; if (rh == null || rh.tid != getthreadid(current)) cachedholdcounter = rh = readholds.get(); else if (rh.count == 0) readholds.set(rh); rh.count++; } return 1; } return fulltryacquireshared(current); }
这里分析tryacquireshared()方法
释放锁
public void unlock() { sync.releaseshared(1); } public final boolean releaseshared(int arg) { if (tryreleaseshared(arg)) { doreleaseshared(); return true; } return false; } protected final boolean tryreleaseshared(int unused) { thread current = thread.currentthread(); if (firstreader == current) { // assert firstreaderholdcount > 0; if (firstreaderholdcount == 1) firstreader = null; else firstreaderholdcount--; } else { holdcounter rh = cachedholdcounter; if (rh == null || rh.tid != getthreadid(current)) rh = readholds.get(); int count = rh.count; if (count <= 1) { readholds.remove(); if (count <= 0) throw unmatchedunlockexception(); } --rh.count; } for (;;) { int c = getstate(); int nextc = c - shared_unit; if (compareandsetstate(c, nextc)) // releasing the read lock has no effect on readers, // but it may allow waiting writers to proceed if // both read and write locks are now free. return nextc == 0; } }
分析tryreleaseshared()方法
获取锁和释放锁的源码部分代码就分析放到这里,接下来用代码时间看看reentrantreadwritelock的使用效果测试。
public class readwritelocktest { private static reentrantreadwritelock readwritelock = new reentrantreadwritelock(); private static executorservice executorservice = executors.newcachedthreadpool(); //读操作 public static void read(){ try {
//加读锁 readwritelock.readlock().lock(); system.out.println(thread.currentthread().getname() + " is reading " + system.currenttimemillis()); thread.sleep(1000); } catch (interruptedexception e){ }finally { readwritelock.readlock().unlock(); } } //写操作 public static void write() { try {
//加写锁 readwritelock.writelock().lock(); system.out.println(thread.currentthread().getname() + " is writing "+ system.currenttimemillis()); thread.sleep(1000); } catch (interruptedexception e){ }finally { readwritelock.writelock().unlock(); } } public static void main(string[] args) { for (int i = 0; i < 3; i++) { executorservice.execute(new runnable() { @override public void run() { readwritelocktest.read(); } }); } for (int i = 0; i < 3; i++) { executorservice.execute(new runnable() { @override public void run() { readwritelocktest.write(); } }); } } }
执行结果如下:
pool-1-thread-2 is reading 1549002279198
pool-1-thread-1 is reading 1549002279198
pool-1-thread-3 is reading 1549002279198
pool-1-thread-4 is writing 1549002280208
pool-1-thread-5 is writing 1549002281214
pool-1-thread-6 is writing 1549002282224
可以看到,thread1,2,3在读时,是同时执行。thread4,5,6在写操作是,都差不多间隔1000毫秒。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
浅析我对 String、StringBuilder、StringBuffer 的理解
使用IDEA搭建SSM框架的详细教程(spring + springMVC +MyBatis)
Springboot整合freemarker 404问题解决方案
引入mybatis-plus报 Invalid bound statement错误问题的解决方法
网友评论