[英]Read/write lock is slower than synchronized, even when only reading?
我有以下代碼 ArrayList 實現
public class LongArrayListUnsafe {
public static void main(String[] args) {
LongArrayList dal1 = LongArrayList.withElements();
for (int i = 0; i < 1000; i++)
dal1.add(i);
// Runtime.getRuntime().availableProcessors()
ExecutorService executorService = Executors.newFixedThreadPool(4);
long start = System.nanoTime();
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++)
dal1.size();
for (int i = 0; i < 1000; i++)
dal1.get(i % 100);
}
});
}
executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
System.out.println("mayor disaster!");
}
}
class LongArrayList {
private long[] items;
private int size;
public LongArrayList() {
reset();
}
public static LongArrayList withElements(long...initialValues) {
LongArrayList list = new LongArrayList();
for (long l: initialValues)
list.add(l);
return list;
}
// Number of items in the double list
public synchronized int size() {
return size;
}
// Return item number i
public synchronized long get(int i) {
if (0 <= i && i < size)
return items[i];
else
throw new IndexOutOfBoundsException(String.valueOf(i));
}
// Add item x to end of list
public synchronized LongArrayList add(long x) {
if (size == items.length) {
long[] newItems = new long[items.length * 2];
for (int i = 0; i < items.length; i++)
newItems[i] = items[i];
items = newItems;
}
items[size] = x;
size++;
return this;
}
現在,這個並發驅動程序代碼只是讀取已經生成的列表。這進行得非常快。 但是我想知道我是否可以使用讀寫鎖更快地執行此只讀操作。 在大小和獲取方面,這看起來像這樣:
synchronized public int size() {
readWriteLock.readLock().lock();
int ret = this.size.get();
readWriteLock.readLock().unlock();
return ret;
}
和
public long get(int i) {
readWriteLock.readLock().lock();
if (0 <= i && i < size.get()) {
long ret = items.get(i);
readWriteLock.readLock().unlock();
return ret;
} else {
throw new IndexOutOfBoundsException(String.valueOf(i));
}
}
但是,使用讀寫鎖會變慢,當我添加更多線程時會更慢。 為什么是這樣? 當我的驅動程序代碼只是讀取時,線程應該或多或少地無限制地訪問方法?
java.util.concurrent.locks.ReadWriteLock本質上比諸如synchronized
類的互斥鎖更復雜。 該類的文檔說明了這一點。 讀寫語義的開銷可能大於return this.size;
, 或return this.items[i];
,即使有周圍的邊界檢查。
讓我們也特別看看你的提議。 你想替換原來的
public synchronized int size() {
return size;
}
與提案
synchronized public int size() { // <-- locks exclusively/mutually on "this"
readWriteLock.readLock().lock(); // <-- locks on readWriteLock.readLock()
int ret = this.size.get(); // <-- is size and AtomicInteger now?
readWriteLock.readLock().unlock();
return ret;
}
我認為使用synchronized
是一個錯字,或者它會給等式添加另一個鎖。 另外,我假設this.size.get();
應該是this.size;
. (在這種情況下使用 AttomicInteger 作為大小沒有意義並增加了額外的成本)。 如果我的假設是正確的,您的實際建議將是:
public int size() {
readWriteLock.readLock().lock();
int ret = this.size;
readWriteLock.readLock().unlock();
return ret;
}
public long get(int i) {
readWriteLock.readLock().lock();
if (0 <= i && i < this.size) {
long ret = items[i];
readWriteLock.readLock().unlock();
return ret;
} else {
throw new IndexOutOfBoundsException(String.valueOf(i));
}
}
public LongArrayList add(long x) {
readWriteLock.writeLock().lock();
if (size == items.length) {
long[] newItems = new long[items.length * 2];
for (int i = 0; i < items.length; i++)
newItems[i] = items[i];
this.items = newItems;
}
items[size] = x;
size++;
readWriteLock.writeLock().unlock();
return this;
}
get(int)
是危險的。 如果拋出IndexOutOfBoundException
,則讀鎖將永遠保持鎖定狀態。 這不會減慢進一步讀取的速度,但它會使所有未來的add(long)
調用保持等待。 如果使用鎖,建議與finally
結合使用,以確保它被解鎖:
public long get(int i) {
readWriteLock.readLock().lock();
try {
if (0 <= i && i < size) {
return items[i];
}
throw new IndexOutOfBoundsException(String.valueOf(i));
}
finally {
readWriteLock.readLock().unlock();
}
}
public LongArrayList add(long x) {
readWriteLock.writeLock().lock();
try {
if (size == items.length) {
long[] newItems = new long[items.length * 2];
for (int i = 0; i < items.length; i++)
newItems[i] = items[i];
items = newItems;
}
items[size] = x;
size++;
}
finally {
readWriteLock.writeLock().unlock();
}
return this;
}
如前所述,如果您閱讀的內容遠遠多於您編寫的內容,則使用synchronized
可能會更高效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.