Java读写锁ReadWriteLock

一、前言

在多线程开发中,我们更多关注的是多并发情况下,修改操作不会因为并发而产生错误的情况,比如1000个线程对一个参数同时加1,最终得到的是小于1000的数字。这样的情况下我们有很多方法来保证其线程安全,比如使用synchronized关键字或者使用ava.util.concurrent包内部的类或者方法。
但其实还有一种情况,同时存在读写并发的情形,这个时候我们希望读写分离,就是对于读取这个动作来说,可以同时有多个线程同时去读取这个资源,但是对于写这个动作来说,只能同时有一个线程来操作,而且同时,当有一个写线程在操作这个资源的时候,其他的读线程是不能来操作这个资源的,这样就极大的发挥了多线程的特点,能很好的将多线程的能力发挥出来。
针对这个需求,java提供了ReadWriteLock这个接口就为我们实现了,他的实现类ReentrantReadWriteLock我们可以很简单的来实现刚才的效果。

二、ReadWriteLock

我们先通过一个例子看一下,先建一个产品价格类

public class ProductPrice {
    //现在产品价格
    private double nowprice;
    //锁
    private ReadWriteLock lock = new ReentrantReadWriteLock();;
    //修改价格
    public void setPrice(double price){
        lock.writeLock().lock();
        this.nowprice = price;
        lock.writeLock().unlock();
    }
    //获取当前价格
    public double getPrice(){
        lock.readLock().lock();
        double value = this.nowprice;
        lock.readLock().unlock();
        return value;
    }
    //将价格自增1000
    public void add(){
        lock.writeLock().lock();
        for(int i=0;i<1000;i++){
            this.nowprice = this.nowprice + 1;
        }
        lock.writeLock().unlock();
    }
}

这其中set和add使用了write锁,get使用了read锁
然后再建分辨建一个Reader类和Writer类来模拟并发读写操作

public class Reader implements Runnable {

    private ProductPrice productPrice;

    public Reader(ProductPrice productPrice) {
        this.productPrice = productPrice;
    }
    @Override
    public void run(){
        System.out.printf("%s: 此时产品价格: %f\n", Thread.currentThread().getName(), productPrice.getPrice());
    }

}

Writer类使用了10ms的延迟,保证在写操作在读操作之间进行。

public class Writer implements Runnable {

    private ProductPrice productPrice;

    public Writer(ProductPrice productPrice) {
        this.productPrice = productPrice;
    }

    @Override
    public void run() {
        try{
            Thread.sleep(10);
        }catch(Exception e){
            e.printStackTrace();
        }
        double price = Math.random() * 10;
        productPrice.setPrice(price);
        System.out.println("Writer: Prices have been modified:"+price);
    }
}

最后使用一个Test类检测一下

public class TestSingleObject {
    public static void main(String[] args) {
        ProductPrice productPrice = new ProductPrice();

        Writer writer = new Writer(productPrice);
        Thread threadWriter = new Thread(writer);
        threadWriter.start();

        Reader readers[] = new Reader[100];
        Thread threadsReader[] = new Thread[100];
        for (int i = 0; i < 100; i++){
            readers[i] = new Reader(productPrice);
            threadsReader[i] = new Thread(readers[i]);
            threadsReader[i].start();
        }
        System.out.println("----------------------"+productPrice.getPrice());
    }
}

执行结果如下:

Thread-1: 此时产品价格: 0.000000
Thread-100: 此时产品价格: 3.702643
----------------------3.7026426089474764
Thread-99: 此时产品价格: 3.702643
Thread-98: 此时产品价格: 3.702643
Thread-97: 此时产品价格: 3.702643
Thread-96: 此时产品价格: 3.702643
Thread-95: 此时产品价格: 3.702643
Thread-94: 此时产品价格: 3.702643
Thread-93: 此时产品价格: 3.702643
Thread-92: 此时产品价格: 3.702643
Thread-91: 此时产品价格: 3.702643
Thread-90: 此时产品价格: 3.702643
Thread-89: 此时产品价格: 3.702643
Writer: Prices have been modified:3.7026426089474764
Thread-88: 此时产品价格: 3.702643
Thread-87: 此时产品价格: 3.702643
Thread-86: 此时产品价格: 3.702643
Thread-85: 此时产品价格: 3.702643
Thread-84: 此时产品价格: 3.702643
Thread-83: 此时产品价格: 3.702643
Thread-82: 此时产品价格: 3.702643
Thread-81: 此时产品价格: 3.702643
Thread-80: 此时产品价格: 3.702643
Thread-79: 此时产品价格: 3.702643
Thread-78: 此时产品价格: 3.702643
Thread-77: 此时产品价格: 3.702643
Thread-76: 此时产品价格: 3.702643
Thread-75: 此时产品价格: 3.702643
Thread-74: 此时产品价格: 3.702643
Thread-73: 此时产品价格: 3.702643
Thread-72: 此时产品价格: 0.000000
Thread-71: 此时产品价格: 0.000000
Thread-70: 此时产品价格: 0.000000
Thread-69: 此时产品价格: 0.000000
Thread-68: 此时产品价格: 0.000000
Thread-67: 此时产品价格: 0.000000
Thread-66: 此时产品价格: 0.000000
Thread-65: 此时产品价格: 0.000000
Thread-64: 此时产品价格: 0.000000
Thread-63: 此时产品价格: 0.000000
Thread-62: 此时产品价格: 0.000000
Thread-61: 此时产品价格: 0.000000
Thread-60: 此时产品价格: 0.000000
Thread-59: 此时产品价格: 0.000000
Thread-58: 此时产品价格: 0.000000
Thread-57: 此时产品价格: 0.000000
Thread-56: 此时产品价格: 0.000000
Thread-55: 此时产品价格: 0.000000
Thread-54: 此时产品价格: 0.000000
Thread-53: 此时产品价格: 0.000000
Thread-52: 此时产品价格: 0.000000
Thread-51: 此时产品价格: 0.000000
Thread-50: 此时产品价格: 0.000000
Thread-49: 此时产品价格: 0.000000
Thread-48: 此时产品价格: 0.000000
Thread-47: 此时产品价格: 0.000000
Thread-46: 此时产品价格: 0.000000
Thread-45: 此时产品价格: 0.000000
Thread-44: 此时产品价格: 0.000000
Thread-43: 此时产品价格: 0.000000
Thread-42: 此时产品价格: 0.000000
Thread-41: 此时产品价格: 0.000000
Thread-40: 此时产品价格: 0.000000
Thread-39: 此时产品价格: 0.000000
Thread-38: 此时产品价格: 0.000000
Thread-37: 此时产品价格: 0.000000
Thread-36: 此时产品价格: 0.000000
Thread-35: 此时产品价格: 0.000000
Thread-34: 此时产品价格: 0.000000
Thread-33: 此时产品价格: 0.000000
Thread-32: 此时产品价格: 0.000000
Thread-31: 此时产品价格: 0.000000
Thread-30: 此时产品价格: 0.000000
Thread-29: 此时产品价格: 0.000000
Thread-28: 此时产品价格: 0.000000
Thread-27: 此时产品价格: 0.000000
Thread-26: 此时产品价格: 0.000000
Thread-25: 此时产品价格: 0.000000
Thread-24: 此时产品价格: 0.000000
Thread-23: 此时产品价格: 0.000000
Thread-22: 此时产品价格: 0.000000
Thread-21: 此时产品价格: 0.000000
Thread-20: 此时产品价格: 0.000000
Thread-19: 此时产品价格: 0.000000
Thread-18: 此时产品价格: 0.000000
Thread-17: 此时产品价格: 0.000000
Thread-16: 此时产品价格: 0.000000
Thread-15: 此时产品价格: 0.000000
Thread-14: 此时产品价格: 0.000000
Thread-13: 此时产品价格: 0.000000
Thread-12: 此时产品价格: 0.000000
Thread-11: 此时产品价格: 0.000000
Thread-10: 此时产品价格: 0.000000
Thread-9: 此时产品价格: 0.000000
Thread-8: 此时产品价格: 0.000000
Thread-7: 此时产品价格: 0.000000
Thread-6: 此时产品价格: 0.000000
Thread-5: 此时产品价格: 0.000000
Thread-4: 此时产品价格: 0.000000
Thread-3: 此时产品价格: 0.000000
Thread-2: 此时产品价格: 0.000000

Process finished with exit code 0

我们可以发现100个线程中,自第73个开始价格被变更了,读写操作是互斥执行的,我们再使用add自增的方法来验证一下。

public class Writer implements Runnable {

    private ProductPrice productPrice;

    public Writer(ProductPrice productPrice) {
        this.productPrice = productPrice;
    }

    @Override
    public void run() {
        try{
            Thread.sleep(10);
        }catch(Exception e){
            e.printStackTrace();
        }
        //productPrice.setPrice(price);
        productPrice.add();
    }
}

将Writer类中的setPrice方法改为执行add自增1000的方法,然后再使用测试类得到结果

Thread-1: 此时产品价格: 0.000000
----------------------1000.0
Thread-100: 此时产品价格: 1000.000000
Thread-99: 此时产品价格: 1000.000000
Thread-98: 此时产品价格: 1000.000000
Thread-97: 此时产品价格: 1000.000000
Thread-96: 此时产品价格: 1000.000000
Thread-95: 此时产品价格: 1000.000000
Thread-94: 此时产品价格: 1000.000000
Thread-93: 此时产品价格: 1000.000000
Thread-92: 此时产品价格: 1000.000000
Thread-91: 此时产品价格: 1000.000000
Thread-90: 此时产品价格: 1000.000000
Thread-89: 此时产品价格: 1000.000000
Thread-88: 此时产品价格: 1000.000000
Thread-87: 此时产品价格: 1000.000000
Thread-86: 此时产品价格: 1000.000000
Thread-85: 此时产品价格: 1000.000000
Thread-84: 此时产品价格: 0.000000
Thread-83: 此时产品价格: 0.000000
Thread-82: 此时产品价格: 0.000000
Thread-81: 此时产品价格: 0.000000
Thread-80: 此时产品价格: 0.000000
Thread-79: 此时产品价格: 0.000000
Thread-78: 此时产品价格: 0.000000
Thread-77: 此时产品价格: 0.000000
Thread-76: 此时产品价格: 0.000000
Thread-75: 此时产品价格: 0.000000
Thread-74: 此时产品价格: 0.000000
Thread-73: 此时产品价格: 0.000000
Thread-72: 此时产品价格: 0.000000
Thread-71: 此时产品价格: 0.000000
Thread-70: 此时产品价格: 0.000000
Thread-69: 此时产品价格: 0.000000
Thread-68: 此时产品价格: 0.000000
Thread-67: 此时产品价格: 0.000000
Thread-66: 此时产品价格: 0.000000
Thread-65: 此时产品价格: 0.000000
Thread-64: 此时产品价格: 0.000000
Thread-63: 此时产品价格: 0.000000
Thread-62: 此时产品价格: 0.000000
Thread-61: 此时产品价格: 0.000000
Thread-60: 此时产品价格: 0.000000
Thread-59: 此时产品价格: 0.000000
Thread-58: 此时产品价格: 0.000000
Thread-57: 此时产品价格: 0.000000
Thread-56: 此时产品价格: 0.000000
Thread-55: 此时产品价格: 0.000000
Thread-54: 此时产品价格: 0.000000
Thread-53: 此时产品价格: 0.000000
Thread-52: 此时产品价格: 0.000000
Thread-51: 此时产品价格: 0.000000
Thread-50: 此时产品价格: 0.000000
Thread-49: 此时产品价格: 0.000000
Thread-48: 此时产品价格: 0.000000
Thread-47: 此时产品价格: 0.000000
Thread-46: 此时产品价格: 0.000000
Thread-45: 此时产品价格: 0.000000
Thread-44: 此时产品价格: 0.000000
Thread-43: 此时产品价格: 0.000000
Thread-42: 此时产品价格: 0.000000
Thread-41: 此时产品价格: 0.000000
Thread-40: 此时产品价格: 0.000000
Thread-39: 此时产品价格: 0.000000
Thread-38: 此时产品价格: 0.000000
Thread-37: 此时产品价格: 0.000000
Thread-36: 此时产品价格: 0.000000
Thread-35: 此时产品价格: 0.000000
Thread-34: 此时产品价格: 0.000000
Thread-33: 此时产品价格: 0.000000
Thread-32: 此时产品价格: 0.000000
Thread-31: 此时产品价格: 0.000000
Thread-30: 此时产品价格: 0.000000
Thread-29: 此时产品价格: 0.000000
Thread-28: 此时产品价格: 0.000000
Thread-27: 此时产品价格: 0.000000
Thread-26: 此时产品价格: 0.000000
Thread-25: 此时产品价格: 0.000000
Thread-24: 此时产品价格: 0.000000
Thread-23: 此时产品价格: 0.000000
Thread-22: 此时产品价格: 0.000000
Thread-21: 此时产品价格: 0.000000
Thread-20: 此时产品价格: 0.000000
Thread-19: 此时产品价格: 0.000000
Thread-18: 此时产品价格: 0.000000
Thread-17: 此时产品价格: 0.000000
Thread-16: 此时产品价格: 0.000000
Thread-15: 此时产品价格: 0.000000
Thread-14: 此时产品价格: 0.000000
Thread-13: 此时产品价格: 0.000000
Thread-12: 此时产品价格: 0.000000
Thread-11: 此时产品价格: 0.000000
Thread-10: 此时产品价格: 0.000000
Thread-9: 此时产品价格: 0.000000
Thread-8: 此时产品价格: 0.000000
Thread-7: 此时产品价格: 0.000000
Thread-6: 此时产品价格: 0.000000
Thread-5: 此时产品价格: 0.000000
Thread-4: 此时产品价格: 0.000000
Thread-2: 此时产品价格: 0.000000
Thread-3: 此时产品价格: 0.000000

可以看出从第85个线程Price价格直接更改到了1000,没有出现0-1000之间的数字,这说明锁的机制保证了add方法执行的时候对读进行了阻塞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值