我在试着理解ReadWriteLock。这段代码将只在IDE中工作。复制和粘贴。试着自己去做
class ReadWrite {
private static final ReadWriteLock LOCK = new ReentrantReadWriteLock();
private static final Lock READ_LOCK = LOCK.readLock();
private static final Lock WRITE_LOCK = LOCK.writeLock();
private static final int[] ARR = new int[1];
int i = 0;
Integer read(){
Integer value = null;
try{
READ_LOCK.lock();
value = ARR[0];
}catch (Exception e){
e.printStackTrace();
}finally {
READ_LOCK.unlock();
}
return value;
}
void write(){
try{
WRITE_LOCK.lock();
ARR[0] = i++;
}catch (Exception e){
e.printStackTrace();
}finally {
WRITE_LOCK.unlock();
}
}
}我正试着做一个性能测试。
AtomicInteger atomicInteger = new AtomicInteger(0);
ReadWrite rw = new ReadWrite();
// read 10 millions times
Runnable r1 = () -> IntStream.rangeClosed(1, 10_000_000).forEach(i -> {
if(rw.read() > 0)
atomicInteger.incrementAndGet();
});
Runnable r2 = rw::write;
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
Thread[] threads = new Thread[10];
long before = System.currentTimeMillis();
scheduledExecutorService.scheduleAtFixedRate(r2, 1, 1, TimeUnit.MICROSECONDS);
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(r1);
threads[i].start();
}
for (int i = 0; i < 10; i++) {
threads[i].join();
}
System.out.println("Time Taken :: " + (System.currentTimeMillis() - before));
System.out.println("No fo reads :: " + atomicInteger.get());做了几次测试。
案例1:
当我使用READ_LOCK阅读时,它需要12秒才能完成。没有读取是100000000。
案例2:
当我同时使用WRITE_LOCK进行读写(本例中没有使用READ_LOCK)时,测试只需2.5秒。没有读取是100000000。
我在想,使用单独的锁可以提高性能。
这里发生什么事情?我犯了什么错?
发布于 2021-04-22 20:18:57
您正在运行read() 1000万次(* 10个线程)。只运行一次write()。写入所用时间为2.5秒,因为只有在没有带有读锁的线程时,它才能接受写锁。
此外,正如@Burak提到的,您没有在这里测量正确的东西。
您应该使用读锁运行同一方法一次,用写锁运行一次。例如,使用10个线程运行此方法。例如,该方法将迭代1到1000万次。
此外,您正在计算在测试中创建线程的时间(这不是锁机制的一部分)。您应该在前面创建线程)
然后,您将看到写锁方法比读锁慢。为什么?因为当线程接受写锁时,只有这个线程才能执行方法代码。在读取锁的情况下,所有10个线程都将并行运行该方法。
发布于 2021-04-23 08:59:45
ReadWriteLock的文档提到了以下内容:
此外,如果读操作太短,读写锁实现的开销(本质上比互斥锁更复杂)可以控制执行成本,特别是因为许多读写锁实现仍然通过一小部分代码序列化所有线程。最终,只有分析和测量才能确定读写锁的使用是否适合您的应用程序。
您的读取确实非常快,因此您正在观察读写锁在简单锁上的开销。
读写锁的实现涉及什么?首先,实际上有两个锁。读取锁可以由多个线程获取,这使得它不同于简单的可重入锁,并且它必须检查写锁在试图锁定时是否已锁定。在试图锁定时,写入器锁必须检查没有锁定的读取器,但它与单线程可重入锁类似。
对于细粒度的访问,例如在您的示例中,读写锁是不值得的。当访问一组数据(如“页面”数据)(例如数百或数千个缓存的数据库行)时,开销可能可以忽略不计。
https://stackoverflow.com/questions/67219909
复制相似问题