有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

    }

}

共 (2) 个答案

  1. # 1 楼答案

    感谢Nick和Slaw指出,这不是阅读主导。 我确保有100个递增、100个递减和1000个读取线程

    结果如预期。 REENTRANDREADWRITELOCK的输出为300毫秒 withLock为5000毫秒。

    这是修改后的代码

    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 < 100; i++) {
                Thread increment = new Increment(resources);
                Thread decrement = new Decrement(resources);
                increments.add(increment);
                decrements.add(decrement);
                increment.start();
                decrement.start();
            }
    
            for (int i = 0; i < 1000; i++) {
                Thread read = new Read(resources);
                reads.add(read);
                read.start();
            }
    
            for (int i = 0; i < 100; i++) {
                increments.get(i).join();
                decrements.get(i).join();
            }
    
            for (int i = 0; i < 1000; i++) {
                reads.get(i).join();
            }
            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() {
                    resources.getCounter();
    
    
            }
        }
    
        private static class Increment extends UserThread {
    
            public Increment(Resources resources) {
                super(resources);
            }
    
            public void run() {
                    resources.increment();
    
    
    
            }
        }
    
        private static class Decrement extends UserThread {
    
            public Decrement(Resources resources) {
                super(resources);
            }
    
            public void run() {
                    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 {
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    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();
                }
            }
    
        }
    
    }
    
    
    
    
  2. # 2 楼答案

    这些类型的锁——读写锁——通常经过优化,适合于许多读者和一个或几个作者。他们经常在ops上旋转,期望读取速度快,写入量少。此外,它们还针对请求的公平性或FIFO处理进行了优化,以避免线程暂停

    你做的恰恰相反。您需要编写许多编写器,这会导致过度旋转和其他复杂的方法,适用于多读少写的场景

    简单的锁很简单。它们只是在准备就绪时阻塞所有线程,并且不会发生旋转。它们的缺点是,当它们唤醒多个线程让它们再次入睡时,会造成雪崩效应