与ReentrantLock相比,java ReentrantReadWriteLock的性能非常差
我已经创建了1000个线程用于递增,1000个线程用于递减,1000个线程用于读取值
每增加一个线程,增加值25000倍
每一个减量螺纹,减少值25000倍
每个读取线程读取50000次值
因此,所有操作都是以读取为主的
读取值时,会放置ReadLock
WriteLock用于递增和;使值递减
观察到:ReentrantReadWriteLock大约需要13000毫秒 锁定大约需要3000毫秒。 期望:ReentrantReadWriteLock提供比ReentrantLock快得多的性能
顺便说一句:我个人认为在使用getCounter方法时不需要锁/同步(只是读取值)
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Main {
public static void main(String[] args) throws InterruptedException {
ArrayList<Thread> reads = new ArrayList<>();
ArrayList<Thread> increments = new ArrayList<>();
ArrayList<Thread> decrements = new ArrayList<>();
Resources resources = new Resources();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
Thread read = new Read(resources);
Thread increment = new Increment(resources);
Thread decrement = new Decrement(resources);
reads.add(read);
increments.add(increment);
decrements.add(decrement);
read.start();
increment.start();
decrement.start();
}
for (int i = 0; i < 1000; i++) {
reads.get(i).join();
increments.get(i).join();
decrements.get(i).join();
}
System.out.println(resources.getCounter());
System.out.println(System.currentTimeMillis() - start);
}
private static abstract class UserThread extends Thread {
protected Resources resources;
public UserThread(Resources resources) {
this.resources = resources;
}
}
private static class Read extends UserThread {
public Read(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 50000; i++) {
resources.getCounter();
}
}
}
private static class Increment extends UserThread {
public Increment(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 25000; i++) {
resources.increment();
}
}
}
private static class Decrement extends UserThread {
public Decrement(Resources resources) {
super(resources);
}
public void run() {
for (int i = 0; i < 25000; i++) {
resources.decrement();
}
}
}
private static class Resources {
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
private ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
private ReentrantLock lock = new ReentrantLock();
public int getCounter() {
readLock.lock();
try {
return counter;
} finally {
readLock.unlock();
}
}
private int counter = 0;
public void increment() {
writeLock.lock();
try {
counter++;
} finally {
writeLock.unlock();
}
}
public void decrement() {
writeLock.lock();
try {
counter--;
} finally {
writeLock.unlock();
}
}
}
}
# 1 楼答案
感谢Nick和Slaw指出,这不是阅读主导。 我确保有100个递增、100个递减和1000个读取线程
结果如预期。 REENTRANDREADWRITELOCK的输出为300毫秒 withLock为5000毫秒。
这是修改后的代码
# 2 楼答案
这些类型的锁——读写锁——通常经过优化,适合于许多读者和一个或几个作者。他们经常在ops上旋转,期望读取速度快,写入量少。此外,它们还针对请求的公平性或FIFO处理进行了优化,以避免线程暂停
你做的恰恰相反。您需要编写许多编写器,这会导致过度旋转和其他复杂的方法,适用于多读少写的场景
简单的锁很简单。它们只是在准备就绪时阻塞所有线程,并且不会发生旋转。它们的缺点是,当它们唤醒多个线程让它们再次入睡时,会造成雪崩效应