读写锁分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

多线程是java的一大核心之一,作为一个java工程师,必须把多线程吃透!


提示:以下是本篇文章正文内容,下面案例可供参考

一、读写锁的基本概念

1)首先读写锁是互斥的,两者不能同时在一个线程的同一个资源内存在(比如一个方法内同时存在读锁和写锁,因为借助对象去调用方法,锁粒度的是对象,加之互斥,所以不能同时存在),不然会发生死锁。

2)一个线程获得了某个资源的读锁,其他线程就不能获得这个资源的写锁(这个资源可以抽象为某个对象好理解一些),但是可以获得读锁,这里的读锁可以抽象为对于读操作来说不加锁。

3)一个线程获得了某个资源的写锁,其他资源就不能获取这个资源的读锁和写锁(防止脏读)

4)举个例子,一个类A,分别有三个方法,B()、C()、D(),其中B()加了写锁,C()加了读锁,D()方法中调用了B()和C()方法,此时必然会发生死锁,因为互斥。

二、代码示例

1.同时调用读锁和写锁

代码如下(示例):

class MyCache{
    Map<String,Object> map=new HashMap<>();
    ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    public void put(String key,Object V){
        try {
        	//加了写锁的方法
            readWriteLock.writeLock().lock();
            map.put(key, V);
        }catch (Exception e){
            System.out.println(e.getStackTrace());
        }finally {
            readWriteLock.writeLock().unlock();
        }

    }


    public void get(int key,Object V){

        try {

            readWriteLock.readLock().lock();//加了读锁
            System.out.println(Thread.currentThread().getName() + "即将写入");
            this.put(String.valueOf(key*3),V);//加了写锁
            System.out.println(Thread.currentThread().getName() + "写入完成");

            System.out.println(Thread.currentThread().getName()+"即将读");
            map.get(key); //加了读锁
            System.out.println(Thread.currentThread().getName()+"读完成");

        }catch (Exception e){
            System.out.println(e.getStackTrace());
        }finally {
            readWriteLock.readLock().unlock();
        }
    }
}

main线程:

public class Lock01 {

    public static void main(String[] args) {
        MyCache myCache=new MyCache();
        
        for (int i=0;i<5;i++) {
            int finalI = i;
            new Thread(() -> {
                myCache.get(finalI,finalI*3);
            }).start();
        }
    }
}

结果:出现死锁导致阻塞

F:\jdk11.06\bin\java.exe "
Thread-0即将写入
Thread-1即将写入

2.读锁可以相互兼容

代码如下(示例):

class MyCache{
    Map<String,Object> map=new HashMap<>();
    ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    public void put(String key,Object V){
        try {
            readWriteLock.readLock().lock();
            map.put(key, V);
        }catch (Exception e){
            System.out.println(e.getStackTrace());
        }finally {
            readWriteLock.readLock().lock();
            System.out.println("");
        }
    }


    public void get(int key,Object V){

        try {

            readWriteLock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + "即将写入");
            this.put(String.valueOf(key*3),V);//加了读锁
            System.out.println(Thread.currentThread().getName() + "写入完成");


            System.out.println(Thread.currentThread().getName()+"即将读");
            map.get(key); //加了读锁
            System.out.println(Thread.currentThread().getName()+"读完成");

        }catch (Exception e){
            System.out.println(e.getStackTrace());
        }finally {
            readWriteLock.readLock().unlock();
        }
    }
}

结果:不发生堵塞,多条线程均可获得读锁

Thread-2即将写入
Thread-4即将写入

Thread-3即将写入
Thread-1即将写入
Thread-0即将写入

Thread-0写入完成
Thread-0即将读
Thread-0读完成

Thread-1写入完成
Thread-1即将读
Thread-1读完成

Thread-3写入完成
Thread-3即将读
Thread-3读完成
Thread-2写入完成
Thread-2即将读
Thread-2读完成

Thread-4写入完成
Thread-4即将读
Thread-4读完成

Process finished with exit code 0

总结

读写锁的概念可以通过mysql辅助理解,当锁的粒度是一张表,如果这张表加了读锁,那所有的线程都可以读,却不能写,当加了写锁,其他线程不能写也不能读,只能等待获得写锁的线程释放锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值