Lock锁

锁实现提供了比使用synchronized方法和语句更广泛的锁操作。它们允许更灵活的结构,可能有不同的属性,可能支持多个关联的Condition对象。

锁是用于控制多个线程对共享资源的访问的工具。

通常,锁提供对共享资源的独占访问:一次只有一个线程可以获得锁,并且所有访问共享资源的访问都需要先获得锁。但是,有些锁可能允许并发访问共享资源。例如readwritellock的读锁。

同步方法或语句的使用提供了对每个对象关联的隐式监视器锁的访问,但强制所有锁的获取和释放都以块结构的方式进行:当多个锁被获取时,它们必须以相反的顺序被释放,并且所有的锁都必须在获取锁的同一个词法作用域中被释放。虽然同步方法和语句的作用域机制使使用监视器锁进行编程变得更加容易,并有助于避免许多涉及锁的常见编程错误,但在某些情况下,您需要以更灵活的方式使用锁。

例如,一些用于遍历并发访问的数据结构的算法需要使用“手拉手”或“链锁”:您获取节点A的锁,然后是节点B,然后释放A并获取C,然后释放B并获取D,等等。

Lock接口的实现允许在不同范围内获取和释放锁,并允许以任何顺序获取和释放多个锁,从而允许使用这种技术。

传统synchronized
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

lock.ReadWriteLock();

ReadlriteLock维护一对相关联的锁,一个用于只读操作,一个用于写操作。只要没有写线程,读锁可以被多个读线程同时持有。写锁是排他的。

所有的readwritellock实现必须保证writellock操作的内存同步效果(在Lock接口中指定)也与相关的readLock保持一致。也就是说,成功获取读锁的线程将看到之前发布的写锁的所有更新。

与互斥锁相比,读写锁在访问共享数据时允许更高级别的并发。它利用了一个事实,即虽然一次只有一个线程(写线程)可以修改共享数据,但在许多情况下,任意数量的线程都可以并发地读取数据(因此读取线程)。理论上,使用读写锁所允许的并发性的增加将导致性能的提高,而不是使用互斥锁。在实践中,只有在共享数据的访问模式合适的情况下,这种并发性的增加才能在多处理器上完全实现。

读写锁是否会提高性能的使用互斥锁的频率取决于读取数据被修改相比,读和写操作的持续时间,和争用数据——也就是说,线程的数量,将尝试读或写数据在同一时间。例如,最初用数据填充的集合,在频繁搜索的情况下(例如某种目录)很少修改的集合是使用读写锁的理想候选对象。然而,如果更新变得频繁,那么数据的大部分时间都被独占锁定,并且几乎不会增加并发性。此外,如果读操作太短,读写锁实现的开销(其本质上比互斥锁复杂)可能会主导执行成本,特别是当许多读写锁实现仍然通过一小段代码序列化所有线程时。最终,只有分析和测量才能确定读写锁的使用是否适合您的应用程序

虽然读写锁的基本操作很简单,但实现必须做出许多策略决策,这些决策可能会影响给定应用程序中读写锁的有效性。

这些策略的例子包括:

  • 当读锁和写锁都在等待时,当写锁释放时,决定是授予读锁还是写锁。作者的偏好是普遍的,因为写作被认为是短的和不频繁的。读者偏好不太常见,因为如果读者像预期的那样频繁且长期存在,就会导致写操作的长时间延迟。公平或“有序”的实现也是可能的。

  • 当一个读取器处于活动状态,而一个写入器正在等待时,确定请求读锁的读取器是否被授予读锁。偏爱读器会无限期地延迟写器,而偏爱写器会降低并发的可能性。确定锁是否可重入:具有写锁的线程可以重新获得它吗?它能在持有写锁的同时获得读锁吗?读锁本身是可重入的吗?

  • 写锁可以降级为读锁而不允许写入者介入?读锁是否可以优先升级为写锁,而不是其他等待的读锁或写锁?

在评估给定实现对应用程序的适用性时,应该考虑所有这些因素。

ReadWriteLockTest

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;class ReadWriteLockTest {public static void main(String[] args) {MyCacheLock myCache = new MyCacheLock();//写入操作for (int i = 0; i < 6; i++) {int temp = i;new Thread(() -> {myCache.put(temp + "", temp + "");}, String.valueOf(i)).start();}//读取操作for (int i = 0; i < 6; i++) {int temp = i;new Thread(() -> {myCache.get(temp + "");}, String.valueOf(i)).start();}}
}class MyCacheLock {private final Map<String, Object> map = new HashMap<>();//读写锁private final ReadWriteLock lock = new ReentrantReadWriteLock();// 存,写入的时候只有一个人操作public void get(String key) {lock.readLock().lock();Object o = null;try {System.out.println(Thread.currentThread().getName() + "读取");try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}o = map.get(key);System.out.println(Thread.currentThread().getName() + "读取ok" + o);} catch (Exception e) {e.printStackTrace();} finally {lock.readLock().unlock();}}public void put(String key, Object value) {lock.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + "写入" + key);map.put(key, value);System.out.println(Thread.currentThread().getName() + "写入完毕");} catch (Exception e) {e.printStackTrace();} finally {lock.writeLock().unlock();}}
}

执行结果, 【写入和读取是多发线程,结果打印顺序并不是唯一的,主要在于CPU时间切片选择】

1写入1
1写入完毕
2写入2
2写入完毕
0写入0
0写入完毕
4写入4
4写入完毕
5写入5
5写入完毕
3写入3
3写入完毕
1读取
2读取
0读取
4读取
5读取
3读取
0读取ok0
1读取ok1
4读取ok4
2读取ok2
5读取ok5
3读取ok3

lock.ReadWriteLock使用方法相关推荐

  1. Ubuntu中出现“Could not get lock /var/lib/dpkg/lock”的解决方法

    Ubuntu中出现"Could not get lock /var/lib/dpkg/lock"的解决方法 参考文章: (1)Ubuntu中出现"Could not ge ...

  2. MySQL5.7报错[ERROR] Unix socket lock file is empty /tmp/mysql.sock.lock的解决方法

    MySQL5.7报错[ERROR] Unix socket lock file is empty /tmp/mysql.sock.lock的解决方法 参考文章: (1)MySQL5.7报错[ERROR ...

  3. 记一次MySQL中Waiting for table metadata lock的解决方法

    记一次MySQL中Waiting for table metadata lock的解决方法 参考文章: (1)记一次MySQL中Waiting for table metadata lock的解决方法 ...

  4. Lock锁的方法使用

    文章目录 1 Lock 1.1 lock() 方法 1.2 tryLock()方法与 tryLock(long time, TimeUnit unit)方法 1.3 lockInterruptibly ...

  5. Lock的tryLock()方法

    概述 tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,这个方法无论如何都会立即返回.在拿不到锁时不会一直 ...

  6. Lock锁-------tryLock()方法

    这一次主要学习Lock接口中的**tryLock()**方法. tryLock()方法是有返回值的,返回值是Boolean类型.它表示的是用来尝试获取锁:成功获取则返回true:获取失败则返回fals ...

  7. ReentrantLock中lock/trylock/lockInterruptibly方法的区别及源码解析

    看了几篇关于这三者区别的文章,但都说的不够具体,自己去读了下源码,大概是清楚了三者的功能,不想了解源码的可以跳到最后看总结. 首先,ReentrantLock类中使用了大量的CAS操作,也就是Comp ...

  8. C# 关于线程锁lock的使用方法

    在多线程编程中,可能会有许多线程并发的执行一段代码(代码块A),以提高执行效率.在某些情况下,我们希望A中的代码块(B)同步的执行,即同一时刻只有一个线程执行代码块B,这就需要用到锁(lock).lo ...

  9. 使用synchronized实现Lock接口的lock和unlock方法

    public class TestLock implements Lock {private Object lock = new Object();private long owner = -1;@O ...

  10. Java多线程:synchronized | Volatile 和Lock和ReadWriteLock多方位剖析(一)

    前言 本文站在多线程初中级学习者的角度,较为全面系统的带你一起了解多线程与锁相关的知识点.带你一起解开与锁相关的各种概念.用法.利弊等.比如:synchronized.Volatile.Lock.Re ...

最新文章

  1. 【CTF】实验吧 疑惑的汉字
  2. python编码(六)
  3. 16.刚体碰撞事件监测与处理
  4. 查看安卓keystore别名
  5. vc++ 利用jmail组件收发邮件
  6. 浅析AES和RSA加密算法的区别和适用场景
  7. 四叶草启动linux黑屏,四叶草剧场黑屏进不去解决方法一览
  8. Java三大器之过滤器(Filter)的工作原理和代码演示
  9. 题目1111:单词替换
  10. 【5】Java内存访问重排序vs volatile
  11. jupyter怎么安装jieba_记录 anaconda安装jieba
  12. Wps文档文件转换成pdf,支持doc-docx-ppt-pptx-xls
  13. 远程入侵原装乘用车(上)
  14. 从事人工智能行业,推荐的几本书籍
  15. 大数据实战项目------中国移动运营分析实时监控平台 || 项目背景
  16. Scratch技巧—-使用克隆技术实现菜单按钮
  17. piggy bank 完全背包
  18. 小鹏G3 XPilot ---APA自动泊车系统
  19. 福州计算机就业形势2017,2017上半年福州就业情况分析及下半年就业形势预判
  20. c4d文件库语言包帮助手册,C4D帮助文件的纰漏

热门文章

  1. Dynamics CRM - 使用 JavaScript 操作 Business Process Flow
  2. as 插件GsonFormat用法(json字符串快速生成javabean)
  3. window.open()
  4. MySQL 第七次练习(存储过程函数)
  5. H3C 静态路由的配置
  6. k8s架构以及相关概念普及
  7. React Native常用组件之ListView组件
  8. liunx查询进程下的线程
  9. dubbo整合springmvc 使用 学习二(spring+dubbo+zookeeper单机服务)
  10. Java HashSet和LinkedHashSet的用法