使用Java 8和Lambda简化ReadWriteLock
考慮到舊版Java代碼,無論您在哪里看,帶有l(wèi)ambda表達式的Java 8絕對可以提高質(zhì)量和可讀性。 今天,讓我們看一下ReadWriteLock以及如何使它使用起來更簡單。 假設(shè)我們有一個稱為Buffer的類,該類可以記住隊列中的最后幾條消息,對舊消息進行計數(shù)并丟棄。 實現(xiàn)非常簡單:
現(xiàn)在我們可以putItem() ,但是內(nèi)部recent隊列將僅保留最后一個capacity元素。 但是,它也記住必須丟棄多少項以避免內(nèi)存泄漏。 該類工作正常,但僅在單線程環(huán)境中有效。 我們使用不是線程安全的ArrayDeque和非同步的int 。 盡管對int讀寫是原子的,但不能保證更改在不同線程中可見。 同樣,即使我們將線程安全的BlockingDeque與AtomicInteger一起使用,我們?nèi)匀惶幱诟偁帬顟B(tài)的危險中,因為這兩個變量彼此不同步。
一種方法是synchronize所有方法 ,但這似乎很嚴格。 此外,我們懷疑讀取的數(shù)量大大超過寫入的數(shù)量。 在這種情況下, ReadWriteLock是絕佳的選擇。 它實際上包括兩個鎖-一個用于讀取,一個用于寫入。 實際上,它們都為同一把鎖競爭,而同一把鎖可以同時由一個作者或多個讀者獲得。 因此,當(dāng)沒有人在寫并且只有寫者偶爾阻塞所有讀者時,我們可以進行并發(fā)讀取。 使用synchronized將始終阻止所有其他對象,無論他們做什么。 ReadWriteLock的可悲部分是它引入了許多樣板。 您必須顯式打開一個鎖,并記住在finally塊中對其進行unlock() 。 我們的實現(xiàn)變得難以閱讀:
public class Buffer {private final int capacity;private final Deque<String> recent;private int discarded;private final Lock readLock;private final Lock writeLock;public Buffer(int capacity) {this.capacity = capacity;recent = new ArrayDeque<>(capacity);final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();readLock = rwLock.readLock();writeLock = rwLock.writeLock();}public void putItem(String item) {writeLock.lock();try {while (recent.size() >= capacity) {recent.removeFirst();++discarded;}recent.addLast(item);} finally {writeLock.unlock();}}public List<String> getRecent() {readLock.lock();try {final ArrayList<String> result = new ArrayList<>();result.addAll(recent);return result;} finally {readLock.unlock(); }public int getDiscardedCount() {readLock.lock();try {return discarded;} finally {readLock.unlock();}}public int getTotal() {readLock.lock();try {return discarded + recent.size();} finally {readLock.unlock();}}public void flush() {writeLock.lock();try {discarded += recent.size();recent.clear();} finally {writeLock.unlock();}}}這是在八月8日之前完成的方式。有效,安全且丑陋。 但是,使用lambda表達式,我們可以將橫切關(guān)注點包裝在這樣的實用程序類中:
public class FunctionalReadWriteLock {private final Lock readLock;private final Lock writeLock;public FunctionalReadWriteLock() {this(new ReentrantReadWriteLock());}public FunctionalReadWriteLock(ReadWriteLock lock) {readLock = lock.readLock();writeLock = lock.writeLock();}public <T> T read(Supplier<T> block) {readLock.lock();try {return block.get();} finally {readLock.unlock();}}public void read(Runnable block) {readLock.lock();try {block.run();} finally {readLock.unlock();}}public <T> T write(Supplier<T> block) {writeLock.lock();try {return block.get();} finally {writeLock.unlock();} public void write(Runnable block) {writeLock.lock();try {block.run();} finally {writeLock.unlock();}}}如您所見,我們包裝了ReadWriteLock并提供了一組可使用的實用程序方法。 原則上,我們希望傳遞Runnable或Supplier<T> (具有單個T get()方法的接口),并確保調(diào)用它時已被適當(dāng)?shù)逆i包圍。 我們可以編寫完全相同的包裝器類,而無需使用lambda,但是使用它們可以大大簡化客戶端代碼:
public class Buffer {private final int capacity;private final Deque<String> recent;private int discarded;private final FunctionalReadWriteLock guard;public Buffer(int capacity) {this.capacity = capacity;recent = new ArrayDeque<>(capacity);guard = new FunctionalReadWriteLock();}public void putItem(String item) {guard.write(() -> {while (recent.size() >= capacity) {recent.removeFirst();++discarded;}recent.addLast(item);});}public List<String> getRecent() {return guard.read(() -> {return recent.stream().collect(toList());});}public int getDiscardedCount() {return guard.read(() -> discarded);}public int getTotal() {return guard.read(() -> discarded + recent.size());}public void flush() {guard.write(() -> {discarded += recent.size();recent.clear();});}}看看我們?nèi)绾握{(diào)用guard.read()和guard.write()傳遞應(yīng)該受到保護的代碼段? 看起來很整潔。 順便說一句,您是否注意到我們?nèi)绾问褂胹tream()將任何集合轉(zhuǎn)換為任何其他集合(在這里: Deque into List stream() ? 現(xiàn)在,如果我們提取幾個內(nèi)部方法,則可以使用方法引用來進一步簡化lambda:
public void flush() {guard.write(this::unsafeFlush); }private void unsafeFlush() {discarded += recent.size();recent.clear(); }public List<String> getRecent() {return guard.read(this::defensiveCopyOfRecent); }private List<String> defensiveCopyOfRecent() {return recent.stream().collect(toList()); }這只是利用lambda表達式來改進現(xiàn)有代碼和庫的眾多方法之一。 我們真的很高興他們終于進入Java語言了,同時已經(jīng)出現(xiàn)在其他數(shù)十種JVM語言中。
翻譯自: https://www.javacodegeeks.com/2014/03/simplifying-readwritelock-with-java-8-and-lambdas.html
總結(jié)
以上是生活随笔為你收集整理的使用Java 8和Lambda简化ReadWriteLock的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备案编制是什么意思(备案编制)
- 下一篇: 在Java 8 Lambda中创建自己的