文档章节

java Lock接口解析

pacey
 pacey
发布于 2017/09/05 23:03
字数 1666
阅读 2
收藏 0

提到java中的锁,相信大家都知道它是用来控制多个线程访问共享资源的方式(即锁能防止多个线程同时访问空享资源而出现线程安全问题)。在实践过程中使用最多的也最常见的锁就是 synchronized 在jdk1.5之前也仅仅有这一种锁而已。在jdk1.5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,Lock接口提供了与synchronized关键字类似的同步功能,但需要在使用时手动获取锁和释放锁。虽然Lock接口没有synchronized关键字自动获取和释放锁那么便捷,但Lock接口却具有了锁的可操作性,可中断获取以及超时获取锁等多种非常实用的同步特性,除此之外Lock接口还有两个非常强大的实现类重入锁和读写锁,下面一一讲解这些内容。

Lock接口的使用

Lock lock  = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操作
}finally{
//一定在finally中释放锁
//也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
  lock.ublock();
}

Lock接口与synchronized关键字的区别

  • Lock接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。 
    *Lock接口能被中断地获取锁 与synchronized不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
  • Lock接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。

Lock接口的API

  • void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回。
  • void lockInterruptibly() throws InterruptedException 可中断获取锁,与lock()方法不同之处在于该方法会响应中断,即在锁的获取过程中可以中断当前线程
  • boolean tryLock() 尝试非阻塞的获取锁,调用该方法立即返回,true表示获取到锁
  • boolean tryLock(long time,TimeUnit unit) throws InterruptedException 超时获取锁,以下情况会返回:时间内获取到了锁,时间内被中断,时间到了没有获取到锁。
  • void unlock() 释放锁

了解Lock接口最常用的实现ReentrantLock重入锁

ReentrantLock是Lock接口一种常见的实现,它是支持重进入的锁即表示该锁能够支持一个线程对资源的重复加锁。该锁还支持获取锁时的公平与非公平的选择。 
关于锁的重进入,其实synchronized关键字也支持。如前所述,synchronized关键字也是隐式的支持重进入而对于ReentrantLock而言,对于已经获取到锁的线程,再次调用lock()方法时依然可以获取锁而不被阻塞。 
理解了锁的重进入,现在解释刚刚提到的公平获取锁与非公平获取锁。如果在绝对时间上,先对于锁进行获取的请求一定先被满足,那么这个锁就是公平的,反之就是非公平的。公平的获取锁也就是等待时间最久的线程优先获取到锁。ReentrantLock的构造函数来控制是否为公平锁。

我在第一次了解到公平锁于非公平锁的时候,第一反应是公平锁的效率高,应该使用公平锁。但实际的情况是,非公平的锁的效率远远大于公平锁。

了解Lock接口的实现类ReentrantReadWriteLock读写锁

前面提到的ReentrantLock是排他锁,该锁在同一时刻只允许一个线程来访问,而读写锁在同一时刻允许可以有多个线程来访问,但在写线程访问时,所有的读线程和其他写线程被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过读写锁分离,使得并发性相比一般的排他锁有了很大的提升。

读写锁除了使用在写操作happends-before与读操作以及并发性的提升之外,读写锁也能够简化读写交互场景的编程方式。假设在程序中定义一个共享的用作缓存数据结构,它的大部分时间提供读服务(查询,搜索等)而写操作较少,但写操作之后需要立即对后续的读操作可见。在没有读写锁之前,实现这个功能需要使用等待通知机制(http://blog.csdn.net/canot/article/details/50879963)。无论使用那种方式,目的都是为了写操作立即可见于读操作而避免脏读。但使用读写锁却比等待通知简单明了多了。 
一般情况下,读写锁性能优于排他锁。它能提供更好的并发性和吞吐量。

ReentrantReadWriteLock读写锁的几个特性:

  • 公平选择性
  • 重进入
  • 锁降级

读写锁的示例:缓存

public class Cache{
  static Map<String,Object> map = new HashMap<String,Object>();
  static ReentrantReadWriteLock  rwl = new ReentrantReadWriteLock();
  static Lock rLock = rwl.readLock();
  static Lock wLock = rwl.writeLock();
  //获取一个key对应的value
  public static final Object get(String key){
  r.lock();
  try{
   return map.get(key);
   }finally{
    r.unlock();
    }
  }
  //设置key对应的value并返回旧的value
  public static fianl Object put(String key,Object value){
  w.lock();
  try{
   return map.put(key,value);
   }final{
   w.unlock();
    }
  }
  //清空缓存
  public static fianl void clear(){
  w.lock();
  try{
     map.clear();
   } finally{
    w.unlock();
    }
  }
}

上述缓存示例中,我们使用了一个非线程安全的HashMap作为缓存的时候然后使用读写锁来保证线程安全。Cache使用读写锁提升读操作的并发性,也保证每次写操作对读操作的及时可见性,同时简化了编程方式。

读写锁的锁降级

锁降级是指写锁降级成为读锁。如果当前线程持有写锁,然后将其释放再获取读锁的过程不能称为锁降级。锁降级指的在持有写锁的时候再获取读锁,获取到读锁后释放之前写锁的过程称为锁释放。

锁降级在某些情况下是非常必要的,主要是为了保证数据的可见性。如果当前线程不获取读锁而直接释放写锁,假设此时另外一个线程获取了写锁并修改了数据。那么当前线程无法感知该线程的数据更新。

本文转载自:http://blog.csdn.net/canot/article/details/52050633

共有 人打赏支持
pacey
粉丝 0
博文 25
码字总数 8465
作品 0
闵行
【XML系列】详解JDOM解析XML

【XML系列】详解JDOM解析XML 一、前言 JDOM是Breet Mclaughlin和Jason Hunter两大Java高手的创作成果,2000年初,JDOM作为一个开放源代码项目正式开始研发。JDOM是一种解析XML的Java工具包。...

磊神Ray
2011/11/01
0
0
Java编程基础知识点和技术点归纳

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰
05/23
0
0
What's New in JDK 8 java8新特性汇总

Oracle甲骨文公司终于在2014年3月发布了Java 8正式版,它是java的一个里程牌版本,带来了诸多新特性。 针对这些新特性汇总如下: 一、针对java编程语言(Java Programming Language) 1.lambd...

cloud-coder
2014/04/03
0
4
读书笔记之《Java并发编程的艺术》-java中的锁

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
0
谈java中类的加载、链接和初始化

Java字节代码的表现形式是字节数组(byte[]), 而Java类在JVM中的表现形式是java. lang. Class类的对象。 一个Java类从字节代码到能够在JVM中被运用, 需要经过加载、链接和初始化这三个步骤。...

风一样
2011/08/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

7月13日任务 for、while、break跳出、ontinue结束、exit退出

20.10 for循环 语法:for 变量名 in 条件; do …; done 案例1:计算1到100的和 #!/bin/bashsum=0for i in `seq 1 100`do    sum=$[$sum+$i]    echo $idoneecho $sum 案例2...

吕湘颖
37分钟前
0
0
qemu增量镜像的好处

可以快速恢复,相当于快照的功能。

simpower
44分钟前
0
0
Python3_Appium_QQ 实战

Python3_Appium实战 -海盐 APPium移动自动化测试 样例中 测试的 app 使用的是 QQ; Appium介绍 Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合...

海盐宝宝
44分钟前
0
0
内网穿透利器-ngrok的图文安装

使用场景: 在做微信开发或是调银行或支付宝等支付系统的时候,本地想联调但是对方需要可以访问的域名或是外网IP才可以。但是,在本地如果不在路由器上做映射或是公司没有固定的外网IP。这种...

中凯_凯哥java
49分钟前
2
1
归约与分组 - 读《Java 8实战》

区分Collection,Collector和collect 代码中用到的类与方法用红框标出,可从git库中查看 收集器用作高级归约 // 按货币对交易进行分组Map<Currency, List<Transaction>> currencyListMap = g...

yysue
50分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部