加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – Synchronized vs ReadWriteLock性能

发布时间:2020-12-15 04:31:42 所属栏目:Java 来源:网络整理
导读:我试图证明当有许多读者和只有一些作者时,synchronized会变慢.不知怎的,我证明了相反. RW示例,执行时间为313 ms: package zad3readWriteLockPerformance;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.
我试图证明当有许多读者和只有一些作者时,synchronized会变慢.不知怎的,我证明了相反.

RW示例,执行时间为313 ms:

package zad3readWriteLockPerformance;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main {
    public static long start,end;

    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            end = System.currentTimeMillis();
            System.out.println("Time of execution " + (end - start) + " ms");
        }));
        start = System.currentTimeMillis();
        final int NUMBER_OF_THREADS = 1000;
        ThreadSafeArrayList<Integer> threadSafeArrayList = new ThreadSafeArrayList<>();
        ArrayList<Thread> consumerThreadList = new ArrayList<Thread>();
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            Thread t = new Thread(new Consumer(threadSafeArrayList));
            consumerThreadList.add(t);
            t.start();
        }

        ArrayList<Thread> producerThreadList = new ArrayList<Thread>();
        for (int i = 0; i < NUMBER_OF_THREADS/10; i++) {
            Thread t = new Thread(new Producer(threadSafeArrayList));
            producerThreadList.add(t);
            t.start();

        }



        //  System.out.println("Printing the First Element : " + threadSafeArrayList.get(1));

    }

}
class Consumer implements Runnable {
    public final static int NUMBER_OF_OPERATIONS = 100;
    ThreadSafeArrayList<Integer> threadSafeArrayList;

    public Consumer(ThreadSafeArrayList<Integer> threadSafeArrayList) {
        this.threadSafeArrayList = threadSafeArrayList;
    }

    @Override
    public void run() {
        for (int j = 0; j < NUMBER_OF_OPERATIONS; j++) {
            Integer obtainedElement = threadSafeArrayList.getRandomElement();
        }
    }

}
class Producer implements Runnable {
    public final static int NUMBER_OF_OPERATIONS = 100;
    ThreadSafeArrayList<Integer> threadSafeArrayList;

    public Producer(ThreadSafeArrayList<Integer> threadSafeArrayList) {
        this.threadSafeArrayList = threadSafeArrayList;
    }

    @Override
    public void run() {
        for (int j = 0; j < NUMBER_OF_OPERATIONS; j++) {
            threadSafeArrayList.add((int) (Math.random() * 1000));
        }
    }

}

class ThreadSafeArrayList<E> {
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private final Lock readLock = readWriteLock.readLock();

    private final Lock writeLock = readWriteLock.writeLock();

    private final List<E> list = new ArrayList<>();

    public void add(E o) {
        writeLock.lock();
        try {
            list.add(o);
            //System.out.println("Adding element by thread" + Thread.currentThread().getName());
        } finally {
            writeLock.unlock();
        }
    }

    public E getRandomElement() {
        readLock.lock();
        try {
            //System.out.println("Printing elements by thread" + Thread.currentThread().getName());
            if (size() == 0) {
                return null;
            }
            return list.get((int) (Math.random() * size()));
        } finally {
            readLock.unlock();
        }
    }

    public int size() {
        return list.size();
    }

}

同步示例,执行时间仅为241ms:

package zad3readWriteLockPerformanceZMIENONENENASYNCHRO;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static long start,end;

    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            end = System.currentTimeMillis();
            System.out.println("Time of execution " + (end - start) + " ms");
        }));
        start = System.currentTimeMillis();
        final int NUMBER_OF_THREADS = 1000;
        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
        ArrayList<Thread> consumerThreadList = new ArrayList<Thread>();
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            Thread t = new Thread(new Consumer(list));
            consumerThreadList.add(t);
            t.start();
        }

        ArrayList<Thread> producerThreadList = new ArrayList<Thread>();
        for (int i = 0; i < NUMBER_OF_THREADS / 10; i++) {
            Thread t = new Thread(new Producer(list));
            producerThreadList.add(t);
            t.start();
        }

        //  System.out.println("Printing the First Element : " + threadSafeArrayList.get(1));

    }

}

class Consumer implements Runnable {
    public final static int NUMBER_OF_OPERATIONS = 100;
    List<Integer> list;

    public Consumer(List<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        for (int j = 0; j < NUMBER_OF_OPERATIONS; j++) {
            if (list.size() > 0)
                list.get((int) (Math.random() * list.size()));
        }
    }

}

class Producer implements Runnable {
    public final static int NUMBER_OF_OPERATIONS = 100;
    List<Integer> threadSafeArrayList;

    public Producer(List<Integer> threadSafeArrayList) {
        this.threadSafeArrayList = threadSafeArrayList;
    }

    @Override
    public void run() {
        for (int j = 0; j < NUMBER_OF_OPERATIONS; j++) {
            threadSafeArrayList.add((int) (Math.random() * 1000));
        }
    }

}

当我的读者数量比作者多十倍时,为什么同步收集会更快.如何显示我在许多文章中读到的RW锁的进展?

解决方法

获取ReadWriteLock的实际成本通常比获取简单互斥锁的成本要慢得多. ReadWriteLock的 javadoc进入:

Whether or not a read-write lock will improve performance over the use of a mutual exclusion lock depends on the frequency that the data is read compared to being modified,the duration of the read and write operations,and the contention for the data – that is,the number of threads that will try to read or write the data at the same time. For example,a collection that is initially populated with data and thereafter infrequently modified,while being frequently searched (such as a directory of some kind) is an ideal candidate for the use of a read-write lock. However,if updates become frequent then the data spends most of its time being exclusively locked and there is little,if any increase in concurrency. 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.

因此,您的线程执行非常简单的操作这一事实可能意味着性能主要取决于实际获取锁定所花费的时间.

您的基准测试还有另一个问题,即Math.random是同步的.从javadoc开始:

This method is properly synchronized to allow correct use by more than one thread. However,if many threads need to generate pseudorandom numbers at a great rate,it may reduce contention for each thread to have its own pseudorandom-number generator.

因此,即使您的并发读者在获取ReadWriteLock时没有相互阻塞,他们仍然可能会争夺在Math.random中获取的锁,从而打败了使用ReadWriteLock的一些优势.您可以通过使用ThreadLocalRandom来改进这一点.此类的用法通常应为以下形式:ThreadLocalRandom.current().nextX(…)(其中X为Int,Long等).

此外,正如assylias指出的那样,没有考虑JIT编译和其他运行时怪癖的天真Java基准测试是不可靠的.你应该使用Java Microbenchmarking Harness (JMH)这样的基准测试.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读