前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >读写锁 ReentrantReadWriteLock

读写锁 ReentrantReadWriteLock

作者头像
彼岸舞
发布2020-11-05 14:26:58
5070
发布2020-11-05 14:26:58
举报

排它锁:

  之前的Synchronized和ReentrantLock都是排他锁,默认只有一个线程可以占用

读写锁:

  读写锁,同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读和写都被阻塞,最适宜与读多写少的情况

  通过解释,我们可以知道读写锁,最常用的就是读多写少的场景,读写锁相比于普通的排它锁,提高了很高的读取性能

接口:

ReadWriteLock

通过接口可以看到需要,实现一个读锁,和一个写锁

实现类:

ReemtramtReadWriteLock

 但是他的内部的读锁和写锁,还是实现了Lock接口

演示读写锁,在读多写少的情况下,读写锁,相对于Sync排它锁的性能提升

定义商品实体类

package org.dance.day4.rw;

/**
 * 类说明:商品的实体类
 */
public class GoodsInfo {
    private final String name;
    //总销售额
    private double totalMoney;
    //库存数
    private int storeNumber;

    public GoodsInfo(String name, int totalMoney, int storeNumber) {
        this.name = name;
        this.totalMoney = totalMoney;
        this.storeNumber = storeNumber;
    }

    public double getTotalMoney() {
        return totalMoney;
    }

    public int getStoreNumber() {
        return storeNumber;
    }

    public void changeNumber(int sellNumber){
        this.totalMoney += sellNumber*25;
        this.storeNumber -= sellNumber;
    }
}

定义商品服务接口,获取信息有用于读取,设置用于写入

package org.dance.day4.rw;

/**
 * 类说明:商品的服务的接口
 */
public interface GoodsService {

    //获得商品的信息
    public GoodsInfo getNum();

    //设置商品的数量
    public void setNum(int number);
}

使用内置锁,写一个实现

package org.dance.day4.rw;

import org.dance.tools.SleepTools;

/**
 * 类说明:用内置锁来实现商品服务接口
 */
public class UseSyn implements GoodsService {
    
    private GoodsInfo goodsInfo;
    
    public UseSyn(GoodsInfo goodsInfo) {
        this.goodsInfo = goodsInfo;
    }

    @Override
    public synchronized GoodsInfo getNum() {
        SleepTools.ms(5);
        return this.goodsInfo;
    }

    @Override
    public synchronized void setNum(int number) {
        SleepTools.ms(5);
        goodsInfo.changeNumber(number);

    }

}

工具类

package org.dance.tools;

import java.util.concurrent.TimeUnit;

/**
 * 类说明:线程休眠辅助工具类
 */
public class SleepTools {

    /**
     * 按秒休眠
     * @param seconds 秒数
     */
    public static final void second(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
        }
    }

    /**
     * 按毫秒数休眠
     * @param seconds 毫秒数
     */
    public static final void ms(int seconds) {
        try {
            TimeUnit.MILLISECONDS.sleep(seconds);
        } catch (InterruptedException e) {
        }
    }
}

调用测试类:

package org.dance.day4.rw;


import org.dance.tools.SleepTools;

import java.util.Random;

/**
 * 类说明:对商品进行业务的应用
 */
public class BusiApp {
    /**
     * 读写线程的比例
     */
    static final int readWriteRatio = 10;
    /**
     * 最少线程数
     */
    static final int minthreadCount = 3;

    /**
     * 读操作
     */
    private static class GetThread implements Runnable{
        
        private GoodsService goodsService;

        /**
         * 传入商品
         * @param goodsService
         */
        public GetThread(GoodsService goodsService) {
            this.goodsService = goodsService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            // 读取100次数量
            for(int i=0;i<100;i++){//操作100次
                goodsService.getNum();
            }
            System.out.println(Thread.currentThread().getName()+"读取商品数据耗时:"
             +(System.currentTimeMillis()-start)+"ms");

        }
    }

    /**
     * 写操做
     */
    private static class SetThread implements Runnable{

        private GoodsService goodsService;
        public SetThread(GoodsService goodsService) {
            this.goodsService = goodsService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            Random r = new Random();
            //操作10次
            for(int i=0;i<10;i++){
                SleepTools.ms(50);
                goodsService.setNum(r.nextInt(10));
            }
            System.out.println(Thread.currentThread().getName()
                    +"写商品数据耗时:"+(System.currentTimeMillis()-start)+"ms---------");

        }
    }

    public static void main(String[] args) throws InterruptedException {
        GoodsInfo goodsInfo = new GoodsInfo("Cup",100000,10000);
        // 使用Sync锁
        GoodsService goodsService = new UseSyn(goodsInfo);
        // 启动三个写线程
        for(int i = 0;i<minthreadCount;i++){
            Thread setT = new Thread(new SetThread(goodsService));
            // 每启动一个写线程,就启动10个读线程
            for(int j=0;j<readWriteRatio;j++) {
                Thread getT = new Thread(new GetThread(goodsService));
                getT.start();
            }
            SleepTools.ms(100);
            setT.start();
        }
    }
}

执行结果:

Thread-0写商品数据耗时:3803ms---------
Thread-11写商品数据耗时:3912ms---------
Thread-22写商品数据耗时:4629ms---------
Thread-30读取商品数据耗时:10352ms
Thread-29读取商品数据耗时:12166ms
Thread-19读取商品数据耗时:13184ms
Thread-6读取商品数据耗时:13583ms
Thread-21读取商品数据耗时:13801ms
Thread-18读取商品数据耗时:13832ms
Thread-15读取商品数据耗时:13907ms
Thread-32读取商品数据耗时:14016ms
Thread-28读取商品数据耗时:14022ms
Thread-23读取商品数据耗时:14063ms
Thread-27读取商品数据耗时:14162ms
Thread-13读取商品数据耗时:14323ms
Thread-8读取商品数据耗时:14462ms
Thread-4读取商品数据耗时:14614ms
Thread-3读取商品数据耗时:14619ms
Thread-5读取商品数据耗时:14676ms
Thread-24读取商品数据耗时:14693ms
Thread-25读取商品数据耗时:14698ms
Thread-10读取商品数据耗时:14979ms
Thread-7读取商品数据耗时:15026ms
Thread-14读取商品数据耗时:14955ms
Thread-26读取商品数据耗时:14923ms
Thread-12读取商品数据耗时:15112ms
Thread-17读取商品数据耗时:15174ms
Thread-31读取商品数据耗时:15106ms
Thread-20读取商品数据耗时:15210ms
Thread-9读取商品数据耗时:15340ms
Thread-16读取商品数据耗时:15305ms
Thread-2读取商品数据耗时:15735ms
Thread-1读取商品数据耗时:15835ms

通过执行结果可以清晰的看到,居然花费了10多秒,而且是越后面的线程花费的时间就越长

接下来切换读写锁

package org.dance.day4.rw;


import org.dance.tools.SleepTools;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 类说明:使用读写锁 实现读写分离
 */
public class UseRwLock implements GoodsService {

    private GoodsInfo goodsInfo;

    /**
     * 创建读写锁,默认使用非公平锁
     */
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 获取读锁
     */
    private final Lock readLock = lock.readLock();

    /**
     * 获取写锁
     */
    private final Lock writeLock = lock.writeLock();


    public UseRwLock(GoodsInfo goodsInfo) {
        this.goodsInfo = goodsInfo;
    }

    @Override
    public GoodsInfo getNum() {
        // 添加读锁
        readLock.lock();
        try {
            SleepTools.ms(5);
            return this.goodsInfo;
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public void setNum(int number) {
        // 添加写锁
        writeLock.lock();
        try {
            SleepTools.ms(5);
            goodsInfo.changeNumber(number);
        } finally {
            writeLock.unlock();
        }
    }

}

业务调用代码修改,只修该这一行就可以

// 使用Sync锁
//        GoodsService goodsService = new UseSyn(goodsInfo);
        // 使用读写锁
        GoodsService goodsService = new UseRwLock(goodsInfo);

执行结果:

Thread-1读取商品数据耗时:616ms
Thread-6读取商品数据耗时:623ms
Thread-8读取商品数据耗时:623ms
Thread-3读取商品数据耗时:624ms
Thread-10读取商品数据耗时:622ms
Thread-4读取商品数据耗时:624ms
Thread-7读取商品数据耗时:623ms
Thread-5读取商品数据耗时:623ms
Thread-2读取商品数据耗时:626ms
Thread-9读取商品数据耗时:622ms
Thread-0写商品数据耗时:576ms---------
Thread-13读取商品数据耗时:649ms
Thread-12读取商品数据耗时:650ms
Thread-19读取商品数据耗时:654ms
Thread-14读取商品数据耗时:654ms
Thread-17读取商品数据耗时:654ms
Thread-20读取商品数据耗时:655ms
Thread-21读取商品数据耗时:655ms
Thread-15读取商品数据耗时:654ms
Thread-16读取商品数据耗时:654ms
Thread-18读取商品数据耗时:654ms
Thread-11写商品数据耗时:571ms---------
Thread-22写商品数据耗时:575ms---------
Thread-26读取商品数据耗时:671ms
Thread-30读取商品数据耗时:670ms
Thread-28读取商品数据耗时:670ms
Thread-25读取商品数据耗时:671ms
Thread-29读取商品数据耗时:671ms
Thread-24读取商品数据耗时:672ms
Thread-32读取商品数据耗时:671ms
Thread-31读取商品数据耗时:671ms
Thread-27读取商品数据耗时:671ms
Thread-23读取商品数据耗时:672ms

根据执行结果可以看出,读写锁,在读写分离时使用,相对于Synchronized排他锁来说,性能提升了10倍不止,所以在读多写少的时候,推荐使用读写锁

作者:彼岸舞

时间:2020\11\03

内容关于:并发编程

本文来源于网络,只做技术分享,一概不负任何责任

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 排它锁:
  • 读写锁:
  • 接口:
  • 实现类:
  • 演示读写锁,在读多写少的情况下,读写锁,相对于Sync排它锁的性能提升
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档