Java并发编程(10)-显式锁和读写锁

释放双眼,带上耳机,听听看~!

文章目录

  • 一、显式锁

  • 1.1、什么是显式锁
    * 1.2、Lock和ReentrantLock
    * 1.3、如何使用显示锁

    
    
    1
    2
    1  * 二、读写锁
    2
  • 2.1、为什么使用读写锁
    * 2.2、ReadWriteLock接口和ReentrantReadWriteLock实现类
    * 2.3、使用读写锁



在Java5.0之前,用于调节共享对象访问的机制只有synchronized和volatile。Java5.0之后提供了新的选择:ReentrantLock,即显式锁。显式锁与之前提过的synchronized的同步互斥 机制不太一样,ReentrantLock并不作为内部锁机制的替代,而是当内部锁机制有局限时可供选择的高级特性。
本文总结自《Java并发编程实践》 第十三章 显式锁 。

一、显式锁

1.1、什么是显式锁

在Java5.0之前,用于调节共享对象访问的机制只有synchronized和volatile。Java5.0之后提供了新的选择:ReentrantLock,即显式锁。显式锁与之前提过的synchronized的同步互斥 机制不太一样,ReentrantLock并不作为内部锁机制的替代,而是当内部锁机制有局限时可供选择的高级特性:

  • 1、显式锁可供开发者人工调控,不易出现同步锁的死锁问题
  • 2、显式锁是可轮询的、定时的以及可中断的锁获取操作、非快结构的加锁(对应于synchronized的加锁和释放都是在同一块代码块中)

1.2、Lock和ReentrantLock

  • Lock接口

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作:


1
2
3
4
5
6
7
8
9
10
1public interface Lock {
2    void lock();
3    void lockInterruptibly() throws InterruptedException;//可中断锁(在获取锁的时候可以响应中断)
4    boolean tryLock();                    //轮询锁
5    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;//定时锁
6    void unlock();  //释放锁
7    Condition newCondition();
8}
9
10
  • ReentrantLock类

ReentrantLock 是Lock的一个实现类,将由最近成功获得锁,并且还没有释放该锁的线程所拥有。此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。

1.3、如何使用显示锁

首先思考一下,为什么要使用显式锁呢?了解过synchronized同步锁的朋友应该明白,当A线程持有该锁,并且迟迟不能完成任务时,该锁将一直被A持有且不能释放,那么B线程就需要等待A释放锁,这会形成一个问题,即线程饥饿死锁。如以下代码:


1
2
3
4
5
1public synchronized void function(){
2            //doing something...
3    }
4
5

但是,如果使用显式锁的话,我们可以人为地调控何时去获得锁,何时去释放锁,从而避免了死锁的发生,这就是使用显式锁的原因。


1
2
3
4
5
6
7
8
9
10
11
12
1 Lock lock = new ReentrantLock();
2
3        lock.lock();//由执行到该处的线程获得锁
4
5        try{
6            //doing something
7            //捕获异常进行处理
8        }finally {
9            lock.unlock();//释放锁
10        }
11
12

二、读写锁

2.1、为什么使用读写锁

ReentrantLock是一种标准的互斥锁,最多只有一个线程能拥有它;这样的实现是线程安全的,但是对读和写两种情况都进行了同步限制,那么在频繁读取时,会对性能造成不必要的浪费。所以,读写锁的出现缓解了这样的问题读写锁(ReadWriteLock)的加锁策略允许多个同时存在的读者,但是只允许一个写者。

2.2、ReadWriteLock接口和ReentrantReadWriteLock实现类

特点允许多个线程同时读,允许一个线程写。


1
2
3
4
5
6
1public interface ReadWriteLock {
2    Lock readLock();
3    Lock writeLock();
4}
5
6

1
2
3
4
5
6
1//ReentrantReadWriteLock是默认的非公平读写锁实现
2ReentrantLock lock= new ReentrantReadWriteLock();
3Lock readLock = lock.readLock();//获得读锁
4Lock writeLock = lock.writeLock();//获得写锁
5
6

2.3、使用读写锁


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1public class ReadWriteMap<K,V> {
2    //读写锁
3    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
4    //read lock
5    private Lock readLock = readWriteLock.readLock();
6    //write lock
7    private Lock writeLock = readWriteLock.writeLock();
8    //map
9    private final Map<K,V> map ;
10    //含参构造
11    public ReadWriteMap(Map map){
12        this.map = map;
13    }
14
15    //get方法,使用读锁
16    public V get(K key){
17        readLock.lock();//其他线程只读不写
18        return map.get(key);
19    }
20
21    //put方法,使用写锁
22    public void put(K key,V value){
23        writeLock.lock();//其他线程都不能写
24        map.put(key,value);
25    }
26
27}
28
29

给TA打赏
共{{data.count}}人
人已打赏
安全技术

用node.js从零开始去写一个简单的爬虫

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索