简体   繁体   English

Java 并发——读写锁性能

[英]Java Concurrency - Read Write Lock Performance

I am trying to understand ReadWriteLock.我想了解 ReadWriteLock。 [ This code will just work in your IDE. [此代码仅适用于您的 IDE。 Copy & paste.复制粘贴。 Try to do this yourself ]尝试自己做这件事]

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();
        }
    }

}

I was trying to do a performance test.我正在尝试进行性能测试。

        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());

Ran this test few times.跑了几次这个测试。

Case 1:情况1:

When i use READ_LOCK for reading it takes 12 seconds to complete.当我使用 READ_LOCK 读取时,需要 12 秒才能完成。 no of reads is 100000000 .读取次数为100000000

Case 2:案例二:

When I use WRITE_LOCK for both reading & writing (READ_LOCK not used in this case), it the test takes only 2.5 seconds.当我使用 WRITE_LOCK 进行读写时(在这种情况下不使用 READ_LOCK),测试只需要 2.5 秒。 no of reads is 100000000 .读取次数为100000000

I was thinking having separate locks should improve performance.我在想拥有单独的锁应该可以提高性能。

What is going on here?这里发生了什么? What is the mistake I do?我做错了什么?

You are running read() for 10 millions times (* 10 threads).您正在运行 read() 1000 万次(* 10 个线程)。 and run write() only once.. The write took 2.5 sec because it was able to take the write lock only when there was no thread with the read lock.并且只运行一次 write() 。写入需要 2.5 秒,因为它只有在没有具有读锁的线程时才能获得写锁。

Also, as @Burak was mentioned, you did not measured the right thing here.另外,正如@Burak 提到的那样,您在这里没有测量正确的东西。

You should run same method once with read lock and once with write lock.您应该使用读锁和写锁运行一次相同的方法。 Run this method with 10 threads for example.例如,使用 10 个线程运行此方法。 The method will iterate 1-10 million for example.例如,该方法将迭代 1-10 百万。

In addition, you are calculating the time of creating a thread inside your test (which is not part of the locks mechanism. You should create the threads before)此外,您正在计算在测试中创建线程的时间(这不是锁定机制的一部分。您应该在之前创建线程)

Then you will see that the write lock method is slower than the read lock.然后你会看到写锁方法比读锁慢。 Why?为什么? because when a thread takes the write lock, only this thread will be able to execute the method code.因为当一个线程获得写锁时,只有这个线程才能执行方法代码。 In case of the read lock, all the 10 threads will run the method in parallel在读锁的情况下,所有 10 个线程将并行运行该方法

The documentation of ReadWriteLock mentions this: ReadWriteLock的文档提到了这一点:

Further, if the read operations are too short the overhead of the read-write lock implementation (which is inherently more complex than a mutual exclusion lock) can dominate the execution cost, particularly as many read-write lock implementations still serialize all threads through a small section of code.此外,如果读取操作太短,则读写锁实现的开销(本质上比互斥锁更复杂)会主导执行成本,特别是因为许多读写锁实现仍然通过一个一小段代码。 Ultimately, only profiling and measurement will establish whether the use of a read-write lock is suitable for your application.最终,只有分析和测量才能确定读写锁的使用是否适合您的应用程序。

Your reads are indeed very fast, so you're observing the overhead that a read-write lock has over a simple lock.您的读取确实非常快,因此您正在观察读写锁相对于简单锁的开销。

What's involved in the implementation of a read-write lock?读写锁的实现涉及什么? To start, there are actually two locks.首先,实际上有两个锁。 The read lock may be taken by multiple threads, making it different from a simple reentrant lock, and it must check that the write lock is not locked when trying to lock.读锁可能被多个线程占用,与简单的可重入锁不同,它在尝试加锁时必须检查写锁没有被锁定。 The writer lock must check that there are no locked readers when trying to lock, but it's otherwise similar to a single-threaded reentrant lock.写入者锁在尝试锁定时必须检查没有锁定的读者,但它在其他方面类似于单线程可重入锁。

For fine-grained accesses such as in your example, a read-write lock is not worth it.对于您的示例中的细粒度访问,读写锁是不值得的。 The overhead might become negligible when accessing a bunch of data, such as a "page" of data, eg hundreds or thousands of cached database rows.当访问一堆数据时,开销可能会变得可以忽略不计,例如数据的“页面”,例如数百或数千个缓存的数据库行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM