显示锁

之前在协调对共享对象的访问时可以使用的机制只有synchronized和volatile。java5.0增加了一种新的机制:ReentrantLock。

Lock和ReentrantLock

Lock提供了一种无条件的、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显示的。

ReentrantLock实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。ReentrantLock可重入加锁。

Lock接口的使用形式:

  Lock lock = new ReentrantLock();
    . . .
   lock.lock();
   try{
       //更新对象状态
       //捕获异常,并在必要时恢复不变性条件
   }finally{
       lock.unlock();
   }

说明:1.使用形式比内置锁复杂;

2.使用try-catch或try-finally代码块包含需要加锁的代码块,捕捉异常;

3.必须在finally块中释放锁,否则,如果被保护的代码块抛异常,锁一直无法释放;

轮询锁和定时锁

可轮询的与可定时的锁获取模式是由tryLock实现的,具有更完善的错误恢复机制。

内置锁的死锁恢复只能靠重新启动程序,防止死锁的唯一方法就是在构造程序时避免出现不一致的锁顺序。

可定时的与可轮询的锁提供了另一种选择:避免死锁的发生。如果不能获取所有的锁,它会使你重新获得控制权,释放已经获得的锁,然后重新尝试获得所有锁。

当使用内置锁时,在开始请求锁后,这个操作将无法取消,因此内置锁很难实现带有时间限制的操作。此时可以使用定时锁。

资源的串行访问方法:一个单线程的Executor;使用一个独占锁

可中断的锁获取操作

lockInterruptibly方法能够在获得锁的同时保持对中断的响应:

lock.lockInterruptibly();

非块结构的加锁

内置锁的锁获取和释放都是基于代码块的。类似于ConcurrentHashMap的锁分段技术,在基于散列的容器中实现不同的散列表,以便使用不同的锁。

连锁式加锁(锁耦合):我们可以采用类似的技术降低链表的锁粒度,即为每一个链表节点使用不同的锁,使不同的线程能独立地对链表的不同部分进行操作。每一个节点的锁将保护链接指针以及在该节点中存储的数据,因此当遍历或修改链表时,必须持有该节点上的这个锁,直到获得了下一个节点的锁。

在synchronized和ReentrantLock之间进行选择

在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的,可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。

内置锁与ReentrantLock相比还有一个优点:在线程转储中能给出在哪些调用帧中获得了锁,并能够检测和识别发生死锁的线程。JVM并不知道哪些线程持有ReentrantLock,因此在调试使用ReentrantLock的线程的问题时,将起不到帮助作用。

未来更可能会提升synchronized而不是ReentrantLock的性能,因为synchronized是JVM的内置属性,它能执行一些优化,例如对线程封闭的锁对象的锁消除优化,通过增加锁的粒度来消除内置锁的同步。

读-写锁(ReadWriteLock)

ReentrantLock实现了一种标准的互斥锁:每次最多只有一个线程能持有ReentrantLock,但有时候不必要的限制了并发性。

ReadWriteLock:一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。

ReadWriteLock接口:

public interface ReadWriteLock{

Lock readLock();

Lock writeLock();

}。

在读写锁实现的加锁策略中,允许多个读操作同时进行,但每次只允许一个写操作。ReadWriteLock是一种性能优化,对于在多处理器系统上被频繁读取的数据结构,ReadWriteLock能提高性能。

ReentrantReadWriteLock为这两种锁都提供了可重入的加锁语义,ReentrantReadWriteLock中的写入锁只能有唯一的所有者,并且只能由获得该锁的线程来释放。

当我们只需要一个并发的基于散列的映射,可以使用ConcurrentHashMap;

如果需要对另一种Map实现(例如LinkedHashMap)提供并发性更高的访问,那么可以使用读-写锁来实现:

用读-写锁来包装Map:

public class ReadWriteLock{
   private final Map<k,v> map;
   private final ReadWriteLock lock = new ReentrantReadWriteLock();
   private final Lock r = lock.readLock();
   private final Lock w = lock.writeLock();

   public ReadWriteLock(Map<k,v> map){
        this.map = map;
   }

   public V put(K key, V value){
        w.lock();
        try{
               return map.put(key,value);
         }finally{
              w.unlock();
         }
   }
   //对remove(),putAll(),clear()等方法执行相同的操作

   public V get(Object key){
         r.lock();
         try{
              return map.get(key);
          }fianlly{
                 r.unlock();
           }
   }
    //对其他只读的Map方法执行相同的操作
}
 
时间: 2024-10-10 22:06:57

显示锁的相关文章

Win10一周年更新专业版受限:不显示锁屏等组策略项无效

微软将在9月30日正式发布Win10一周年更新版,该版本在功能上有很多改进,受到了Windows Insider用户的广泛欢迎.然而有些细节也许已经被多数北京赛车PK10忽视,那就是专业版的某些组策略项目被微软设为无效. 以下为具体移除项目: 1.关闭 Microsoft 用户体验 2.不显示Windows提示 3.不显示锁屏 4.禁用来自Windows商店的所有应用 上述项目仍然存在于Windows10专业版中,但你会在项目说明中看到最后一句话有适用范围,一般都是"仅适用于企业版和教育版&qu

Java并发(基础知识)——显示锁和同步工具类

显示锁                                                                                     Lock接口是Java 5.0新增的接口,该接口的定义如下: public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long

多线程并发编程之显示锁ReentrantLock和读写锁

在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock. ReentrantLock概况 ReentrantLock是可重入的锁,它不同于内置锁, 它在每次使用都需要显示的加锁和解锁, 而且提供了更高级的特性:公平锁, 定时锁, 有条件锁, 可轮询锁, 可中断锁. 可以有效避免死锁的活跃性问题.ReentrantLock实现了 Lock接口: public interface Lock { //阻塞直到获得锁或者中

第十三章 显示锁

Java 5.0 提供的新的加锁机制:当内置加锁机制不适合时 , 作为一种可选择的高级功能 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. 13.1 Lock 与 ReentrantLock Lock 中实现的必须提供与内置锁相同的内存可见 性语义, 但在加锁语义,调度算法,顺序保证和性能特性方面有所不同. 13.1.1 轮询锁和定时锁 在内置锁中, 解决死锁的唯一方法是 重新启动程序. 防止死锁的唯一

并发编程(四)显示锁

1.显示锁 Java程序可以依靠synchronized关键字隐式的获取锁实现锁功能,但是它将锁的获取和释放固话了,也就是先获取再释放. (synchronized是语言的特性(内置锁),Lock是一个类 使用的时候需要对其实例化 和方法调用,内存,CPU消耗较大.且JDK中对synchonized的优化已经做的很好,一般情况下没有特殊需求 尽量使用synchonized) 显示锁特性: 1)尝试非阻塞的获取锁:当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取,则成功获取并持有锁: 2)能被

内部锁、显示锁和读写锁

线程同步机制 线程同步机制是一套用于协调线程间的数据访问及活动的机制.该机制用于保障线程安全及实现这些线程的共同目标. java平台提供的线程同步机制: 锁 volatile关键字 final关键字 static关键字 其他(如:Object.wait()/Object.notify()等) 锁机制 锁机制 :将多线程并发访问共享数据转换为串行访问,一个共享数据每次只能被一个线程访问(获得锁),该线程访问结束后(释放锁)其他线程才能对其访问. 锁的获得 : 一个线程在访问数据前必须申请相应的锁.

显示锁和aqs

一.内置锁sync 和 显示锁lock概念 1.synv锁又叫内置锁,不能中断,拿不到无限等待即阻塞: java自带关键字: 隐式可重入: 重入锁:锁对应对象要多次调用对应方法,如递归 2. lock的lockinterruptiply意思是可中断的:语言层面的接口: 其实现类reentrantlock 可重入锁,sync锁显示对应,可以理解为sync关键字在lock接口下的实现: 3.重入锁:锁对应对象要多次调用对应方法,如递归: 可重入锁,sync内置锁,多次获取和释放,计数器加1减1,方法

实现一个显示锁

定义一个lock接口 package com.dwz.concurrency.chapter10; import java.util.Collection; public interface Lock { class TimeOutException extends Exception { public TimeOutException(String message) { super(message); } } void lock() throws InterruptedException; v

并发编程(4)--显示锁和AQS

4.显式锁和AQS   显式锁 Lock接口和核心方法 package com.xiangxue.ch4; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author Administrator * *使用显示锁的范式:一定要在finally中释放锁 */ public class LockDemo { private Lock lock = new