主要并发工具类-ReadWriteLock的使用

2020-02-10  本文已影响0人  飞奔吧牛牛

使用场景:
程序中有如下三种互斥情况:读/读,写/写,读/写。在大多数情况下我们只需要控制读/写,写/写两种情况互斥即可,读/读操作不用做同步。当程序中读/读操作的比例较大时,如果还使用ReentrantLock,则其同步机制会照成大量的排队。可是使用ReadWriteLock可以极大的提高程序的性能。

ReentrantLock和ReadWriteLock使用起来基本一致。下面测试下两者在频繁进行读操作时的性能。
开三个线程分别进行循环10次的写操作,开1000个线程进行读操作。
ReentrantLock 性能测试:

public class P2_ReadWriteLock {
    String name;
    ReentrantLock lock = new ReentrantLock();
//    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void setName(String name) {
        lock.lock();
//        lock.writeLock().lock();
        try {
            this.name = name;
            System.out.println(Thread.currentThread().getName() + " setName " + this.name);
            //假设该类型操作消耗一点时间
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
//            lock.writeLock().unlock();
        }
    }

    public void printName() {
        lock.lock();
//        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " name is " + name);
            //假设该类型操作需要消耗一点时间
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
//            lock.readLock().unlock();
        }
    }

    public static void main(String[] args) {
        P2_ReadWriteLock client = new P2_ReadWriteLock();
        long startTime = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();
        new Date().getTime();
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    client.printName();
                    System.out.println(Thread.currentThread().getName() + " 耗时:" + (System.currentTimeMillis() - startTime));
                }
            }).start();
        }


    }
}

结果:

Thread-999 耗时:11028
Thread-1000 name is Thread-2
Thread-1000 耗时:11039
Thread-1001 name is Thread-2
Thread-1001 耗时:11050
Thread-1002 name is Thread-2
Thread-1002 耗时:11061

ReadWriteLock:

public class P2_ReadWriteLock {
    String name;
//    ReentrantLock lock = new ReentrantLock();
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void setName(String name) {
//        lock.lock();
        lock.writeLock().lock();
        try {
            this.name = name;
            System.out.println(Thread.currentThread().getName() + " setName " + this.name);
            //假设该类型操作消耗一点时间
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
//            lock.unlock();
            lock.writeLock().unlock();
        }
    }

    public void printName() {
//        lock.lock();
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " name is " + name);
            //假设该类型操作需要消耗一点时间
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
//            lock.unlock();
            lock.readLock().unlock();
        }
    }

    public static void main(String[] args) {
        P2_ReadWriteLock client = new P2_ReadWriteLock();
        long startTime = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    client.setName(Thread.currentThread().getName());
                }
            }
        }).start();
        new Date().getTime();
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    client.printName();
                    System.out.println(Thread.currentThread().getName() + " 耗时:" + (System.currentTimeMillis() - startTime));
                }
            }).start();
        }


    }
}

结果:

Thread-561 耗时:448
Thread-552 耗时:448
Thread-559 耗时:448
Thread-551 耗时:448
Thread-549 耗时:448

总结:
当满足读/写互斥,写/写互斥,而读/读不需要互斥,且读/读操作的比例比较大时,换成读写锁更好。

上一篇下一篇

猜你喜欢

热点阅读