20. 锁 Lock

java.util.concurrent.locks.Lock 是一个类似于 synchronized 块的线程同步机制。但是 Lock 比 synchronized 块更加灵活、精细。
顺便说一下,在我的《Java 并发指南》中我对如何实现你自己的锁进行了描述。

Java Lock 例子

既然 Lock 是一个接口,在你的程序里需要使用它的实现类之一来使用它。以下是一个简单示例:

  1. Lock lock = new ReentrantLock();
  2. lock.lock();
  3. //critical section
  4. lock.unlock();

首先创建了一个 Lock 对象。之后调用了它的 lock() 方法。这时候这个 lock 实例就被锁住啦。任何其他再过来调用 lock() 方法的线程将会被阻塞住,直到锁定 lock 实例的线程调用了 unlock() 方法。最后 unlock() 被调用了,lock 对象解锁了,其他线程可以对它进行锁定了。

Java Lock 实现

java.util.concurrent.locks 包提供了以下对 Lock 接口的实现类:

  • ReentrantLock

Lock 和 synchronized 代码块的主要不同点

一个 Lock 对象和一个 synchronized 代码块之间的主要不同点是:

  • synchronized 代码块不能够保证进入访问等待的线程的先后顺序。
  • 你不能够传递任何参数给一个 synchronized 代码块的入口。因此,对于 synchronized 代码块的访问等待设置超时时间是不可能的事情。
  • synchronized 块必须被完整地包含在单个方法里。而一个 Lock 对象可以把它的 lock() 和 unlock() 方法的调用放在不同的方法里。

Lock 的方法

Lock 接口具有以下主要方法:

  • lock()
  • lockInterruptibly()
  • tryLock()
  • tryLock(long timeout, TimeUnit timeUnit)
  • unlock()

lock() 将 Lock 实例锁定。如果该 Lock 实例已被锁定,调用 lock() 方法的线程将会阻塞,直到 Lock 实例解锁。
lockInterruptibly() 方法将会被调用线程锁定,除非该线程被打断。此外,如果一个线程在通过这个方法来锁定 Lock 对象时进入阻塞等待,而它被打断了的话,该线程将会退出这个方法调用。
tryLock() 方法试图立即锁定 Lock 实例。如果锁定成功,它将返回 true,如果 Lock 实例已被锁定该方法返回 false。这一方法永不阻塞。
tryLock(long timeout, TimeUnit timeUnit) 的工作类似于 tryLock() 方法,除了它在放弃锁定 Lock 之前等待一个给定的超时时间之外。

unlock() 方法对 Lock 实例解锁。一个 Lock 实现将只允许锁定了该对象的线程来调用此方法。其他(没有锁定该 Lock 对象的线程)线程对 unlock() 方法的调用将会抛一个未检查异常(RuntimeException)。

21. 读写锁 ReadWriteLock

java.util.concurrent.locks.ReadWriteLock 读写锁是一种先进的线程锁机制。它能够允许多个线程在同一时间对某特定资源进行读取,但同一时间内只能有一个线程对其进行写入。
读写锁的理念在于多个线程能够对一个共享资源进行读取,而不会导致并发问题。并发问题的发生场景在于对一个共享资源的读和写操作的同时进行,或者多个写操作并发进行。
本节只讨论 Java 内置 ReadWriteLock。如果你想了解 ReadWriteLock 背后的实现原理,请参考我的《Java 并发指南》主题中的《读写锁》小节。

ReadWriteLock 锁规则

一个线程在对受保护资源在读或者写之前对 ReadWriteLock 锁定的规则如下:

  • 读锁:如果没有任何写操作线程锁定 ReadWriteLock,并且没有任何写操作线程要求一个写锁(但还没有获得该锁)。因此,可以有多个读操作线程对该锁进行锁定。
  • 写锁:如果没有任何读操作或者写操作。因此,在写操作的时候,只能有一个线程对该锁进行锁定。

ReadWriteLock 实现

ReadWriteLock 是个接口,如果你想用它的话就得去使用它的实现类之一。java.util.concurrent.locks 包提供了 ReadWriteLock 接口的以下实现类:

  • ReentrantReadWriteLock

ReadWriteLock 代码示例

以下是 ReadWriteLock 的创建以及如何使用它进行读、写锁定的简单示例代码:

  1. ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  2. readWriteLock.readLock().lock();
  3. // multiple readers can enter this section
  4. // if not locked for writing, and not writers waiting
  5. // to lock for writing.
  6. readWriteLock.readLock().unlock();
  7. readWriteLock.writeLock().lock();
  8. // only one writer can enter this section,
  9. // and only if no threads are currently reading.
  10. readWriteLock.writeLock().unlock();

注意如何使用 ReadWriteLock 对两种锁实例的持有。一个对读访问进行保护,一个队写访问进行保护。

最新文章

  1. Android常见控件— — —ProgressDialog
  2. 解决 Redis Cluster 扩容故障
  3. hilbert矩阵
  4. 完美解决 未能打开编辑器:Unmatched braces in the pattern.
  5. php导出excel数据
  6. 关于MATLAB处理大数据坐标文件2017622
  7. 自写 zTree搜索功能 -- 关键字查询 -- 递归无限层
  8. 【一天一道LeetCode】#24. Swap Nodes in Pairs
  9. springcloud采坑--Zuul上传文件报java.nio.charset.IllegalCharsetNameException: UTF-8;boundary=sqgzzmMxl1UPdIp0IAYnQgUIAr9yNewVAzKIX
  10. 不在sudoer里解决办法 和 RHEL 挂载NTFS硬盘
  11. skyline添加wfs服务时,弹出错误“no layers were found”!
  12. C# 反射常见用法
  13. Python开发【笔记】:谁偷了我的内存?
  14. SQL Server 2008 存储过程示例
  15. 同步FIFO的设计
  16. HTML一(简介)
  17. python学习笔记之——正则表达式
  18. 【Oozie】ambari安装oozie失败
  19. day5 常用模块json和pickle
  20. {Reship}{Meanshift}Mean Shift Tracking: 2000-2012回顾

热门文章

  1. Android动态添加和移除布局
  2. Thread suspend()挂起resume()恢复
  3. Android Studio使用过程中常见问题及解决方案
  4. [AGC010E] Rearranging [拓扑排序+堆]
  5. Lambda表达式使用2
  6. Pty的字符串(string)
  7. 【POJ 2752 Seek the Name, Seek the Fame】
  8. bzoj1494【Noi2007】生成树计数
  9. NOIP2017赛前模拟11月4日总结:
  10. 解决crlf 和 lf不同带来的冲突问题