读写锁

package com.zc.study;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author zc
 * 读写锁Demo
 * ReentrantReadWriteLock读写锁定义:
 *  1、支持一写多读的同步锁(一把写锁,多把读锁),读写分离,可分别配置读锁和写锁
 *  2、支持分配多个读锁,可以使多个读操作并发执行
 *  注意:读锁和写锁必须来自于同一个ReentrantReadWriteLock对象,这样读写锁才是互斥的
 *
 *  互斥规则:
 *      a、写锁 与 写锁 :互斥,阻塞
 *      b、读锁 与 写锁 :互斥,读锁阻塞写锁,写锁阻塞读锁
 *      c、读锁 与 读锁 : 不互斥,不阻塞;多把读锁可以并发执行
 *
 *  使用场景:在读操作远高于写操作的场景下,可在保证线程安全的情况下大幅提升效率
 */
public class ReentrantReadWriteLockDemo {
    /**创建读写锁对象*/
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    /**从读写锁对象中获取读锁*/
    ReentrantReadWriteLock.ReadLock rLock = lock.readLock();

    /**从读写锁对象获取写锁*/
    ReentrantReadWriteLock.WriteLock wLock = lock.writeLock();

    /**实例化一个对象*/
    final static ReentrantReadWriteLockDemo demo = new ReentrantReadWriteLockDemo();

    public static void main(String[] args) {
        //读操作
        Callable<Integer> write = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                demo.setValue(11);
                return null;
            }
        };

        //写操作
        Callable<Integer> read = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                demo.getValue();
                return null;
            }
        };

        //实例化线程池对象,创建20个线程
        ExecutorService es = Executors.newFixedThreadPool(20);

        //开始时间
        long start = System.currentTimeMillis();

        //分配给写操作2个线程
        for (int i = 0; i < 2; i++) {
            es.submit(write);
        }

        //分配给读操作18个线程
        for (int i = 0; i < 18; i++) {
            es.submit(read);
        }

        es.shutdown();//运行完任务后停止接受新任务

        //判断执行完shutdown命令后,是否运行完毕,如果没有就一直判断,直到所有线程运行完毕为止
        while (true){
            if(es.isTerminated()) {
                break;
            }
        }

        //结束时间
        long end = System.currentTimeMillis();

        //完成时间
        System.out.println(end - start);

    }


    private int value;

    /**读操作*/
    public int getValue() {
        rLock.lock();//拿到读锁
        try {
            try{
                //每次睡眠1s
                Thread.sleep(1000);
            }
             catch (InterruptedException e) {
                e.printStackTrace();
            }
            return value;
        }finally{
            rLock.unlock();//释放读锁
        }
    }

    /**写操作*/
    public void setValue(int value) {
        wLock.lock();//获取写锁
        try {
            try{
                //每次睡眠1s
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.value = value;
        }finally{
            wLock.unlock();//释放写锁
        }

    }
}

测试结果是执行完毕所有代码用时 3s 左右,而我们一共有20个线程同时并发执行,每个写操作和读操作都会睡眠 1s ,而写锁有 2 把,读锁有 18 把,如果读锁和读锁是相互排斥的,那么我们的运行时间应该是 20s 以上,由此可以看到除了 2 把写锁分别耗时 1s 外,所有的读锁同时并发执行,也就是在 1s 内,18个读线程同时并发执行完毕。因此当读多写少,使用读写锁既能保证线程安全,还能提升效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值