天天看点

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

1、隐式锁 对称线程同步 synchronized

    用法:1、在方法声明时使用;2、修饰代码块中使用

    隐式规则

        1、当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行

        2、当一个线程访问object的一个synchronized(this)同步代码块时,其他的线程可以访问该object中的非synchronized(this)同步代码块

        3、synchronized(this)设置的对象锁中,当一个线程访问获取到锁,其他线程对object中相同对象锁的代码块都无法访问

    性能和执行效率:

        同步方法体<同步代码块 <synchronized(this)<同步代码块(byte锁)

    如图1-2

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

图1-2

    关于效率高低的判断,其实记住一点,锁时一个对象,加锁和释放锁都需要资源,对象越小效率越高 

2、显式锁Lock和ReentrantLock

Lock只是一个接口,它规定了锁的基础操作规范

如图2-1所示

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

图2-1

        1、Lock()方法,线程获取锁,如果锁不可用,则禁用当前线程,在获得锁之前,该线程一直处于休眠

        2、unlock()方法,释放锁,一般情况下,每个获取的锁都要对应一个释放锁

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

    其他的方法像是lockInterruptibly、tryLock、tryLock(long time, TimeUnit unit)这几个方法无非就是在获取锁的过程中判断了一些条件,这里需要注意的是,方法中的锁一定要是共有的,如果是独立的锁,那么起不到相应的作用

3、显示锁,读写锁ReadWriteLock和ReentrantReadWriteLock

        ReadWriteLock是一个接口,只有两个方法,readLock()和writeLock(),此处注意,ReadWriteLock并不是Lock的子接口,但是ReadWriteLock中的读写锁都是依靠Lock来进行实现的

读写锁的机制:

    1、读读不互斥:多线程读,并发不堵塞

    2、读写互斥:有线程在写,那么所有的读线程就会堵塞,反过来,有读的线程在使用,写线程就会堵塞

    3、写写互斥:写线程都是互斥的,两个线程去写,谁先拿到锁,就先写

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

图3-1

图3-1中是同时使用读写锁的时候的业务场景,比较经典的缓存场景

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

图3-2

Java中的‘锁’- synchronized、ReentrantLock、ReentrantReadWriteLock

图3-3

图3-2和图3-3则是模拟高并发的情况下的读写锁单独使用的情况下,图3-2的是模拟高并发的单元测试代码,图3-3是读写锁的代码

读写锁和普通锁的区别,

    1、相同点:其实都是一种显式锁,手动加锁和解锁,都比较适合高并发场景

    2、不同点:ReentrantReadWriteLock是对ReentrantLock的一种扩展,ReentrantReadWriteLock适合更加复杂的业务场景,可以实现一个方法的读写分离