java并发编程实战:第十三章----显示锁
一、Lock与ReentrantLock
Lock接口中定义了一种无条件、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的。
1 public interfece Lock
2 {
3 void lock();
4 void lockInterruptibly() throws InterruptedException;
5 boolean tryLock();
6 boolean tryLock(long timeout, TimeUnit unit
7 throw InterruptedException;
8 void unlock();
9 Condition newCondition();
10 }
ReentrantLock实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性。ReentrantLock同样提供了可重入的加锁语义
1 Lock lock = new ReentrantLock();
2 ...
3 lock.lock();
4 try {
5 // 更新对象状态
6 // 捕获异常,并在必要时恢复不变性条件
7 } finally {
8 lock.unlock();//一定要记得在finally块里释放
9 }
1、轮询锁与定时锁
- 轮询锁和定时锁可由tryLock来实现
- 轮询锁,定时锁可以避免死锁的发生
- 轮询锁通过释放已获得的锁,并退回重新尝试获取所有锁(lock.tryLock()),定时锁通过释放已获得的锁,放弃本次操作(lock.tryLock(timeout, unit))来避免死锁
轮循锁
while (true) {
if (fromAcct.lock.tryLock()) {
try {
if (toAcct.lock.tryLock()) {
try {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAcct.debit(amount);
toAcct.credit(amount);
return true;
}
} finally {
toAcct.lock.unlock();
}
}
} finally {
fromAcct.lock.unlock();
}
}
if (System.nanoTime() < stopTime)
return false;
NANOSECONDS.sleep(fixedDelay + rnd.nextLong() % randMod);
}
}
定时锁
public boolean trySendOnSharedLine(String message,
long timeout, TimeUnit unit)
throws InterruptedException {
long nanosToLock = unit.toNanos(timeout)
- estimatedNanosToSend(message);
if (!lock.tryLock(nanosToLock, NANOSECONDS))
return false;
try {
return sendOnSharedLine(message);
} finally {
lock.unlock();
}
}
2、可中断的锁获取操作
- Lock.lockInterruptibly():该锁与lock相似,但可以被中断
- 如果线程未被中断,也不能获取到锁,就会一直阻塞下去,直到获取到锁或发生中断请求
- 定时的lock.tryLock(timeout, unit)同样能响应中断
3、非块结构加锁
- 内置锁是基于块结构的加锁
- Lock可以使块与块交叉实现非块结构的加锁(连锁式加锁或者锁耦合),例:链表中,next节点加锁后,释放pre节点的锁
二、性能考虑因素
竞争性能是可伸缩性的关键因素:如果有越多的资源被耗费在锁的管理和调度上,那么应用程序得到的资源就越少
在Java5.0中,ReentrantLock能提供更高的吞吐量,但在Java6中,二者的吞吐量非常接近
三、公平性
公平锁——Lock fairLock = new ReentrantLock(true);
- 在公平的锁上,线程将按照它们发出请求的顺序来获得锁
- 在非公平的锁上,则允许”插队“:当一个线程请求非公平的锁时,如果在发出请求的同时该锁的状态变为可用,那么这个线程将跳过队列中所有的等待线程并获得这个锁
- 公平性将由于在挂起线程和恢复线程时存在的开销而极大地降低性能(非公平性的锁允许线程在其他线程的恢复阶段进入加锁代码块)
- 当持有锁的时间相对较长,或者请求锁的平局时间间隔较长,那么应该使用公平锁
- 内置锁默认为非公平锁
四、在Synchronized和ReentrantLock之间作出选择
在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized
Synchronized是JVM的内置属性,能执行一些优化,并且基于块结构与特定栈管理,便于检测识别发生死锁。
Java6提供了一个管理和调试接口,锁可以通过该接口进行注册,从而与ReentrantLocks相关的加锁信息就能出现在转储中,并通过其他的管理接口和调试接口来访问
五、读—写ReadWriteLock锁——一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行
对于在多处理器系统上被频繁读取的数据结构,读 - 写锁能够提高性能。而在其他情况下,读 - 写锁的性能比独占锁的性能要略差一些,这是因为它们的复杂性更高
1 public interface ReadWriteLock {
2 Lock readLock();
3 Lock writeLock();
4 }
读写锁的可选实现:
- 释放优先。写入锁释放后,应该优先选择读线程,写线程,还是最先发出请求的线程
- 读线程插队。锁由读线程持有,写线程再等待,再来一个读线程,是继续让读线程访问,还是让写线程访问
- 重入性。读取锁和写入锁是否可重入
- 降级。将写入锁降级为读取锁
- 升级。将读取锁升级为写入锁
在非公平的锁中,线程获得访问许可的顺序是不确定的。写线程降级为读线程是可以的,当从读线程升级为写线程这是不可以的(这样会导致死锁)
java并发编程实战:第十三章----显示锁的更多相关文章
- Java并发编程实战---第六章:任务执行
废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...
- Java并发编程实战 第16章 Java内存模型
什么是内存模型 JMM(Java内存模型)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见. JMM为程序中所有的操作定义了一个偏序关系,称为Happens-Be ...
- 【java并发编程实战】第一章笔记
1.线程安全的定义 当多个线程访问某个类时,不管允许环境采用何种调度方式或者这些线程如何交替执行,这个类都能表现出正确的行为 如果一个类既不包含任何域,也不包含任何对其他类中域的引用.则它一定是无状态 ...
- Java并发编程实战 第8章 线程池的使用
合理的控制线程池的大小: 下面内容来自网络.不过跟作者说的一致.不想自己敲了.留个记录. 要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务.IO ...
- 《Java并发编程实战》第二章 线程安全性 读书笔记
一.什么是线程安全性 编写线程安全的代码 核心在于要对状态訪问操作进行管理. 共享,可变的状态的訪问 - 前者表示多个线程訪问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与 ...
- 《Java并发编程实战》第二章 线程安全 札记
一个.什么是线程安全 编写线程安全的代码 其核心是管理国事访问的操作. 共享,可变的状态的訪问 - 前者表示多个线程訪问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与其规范 ...
- java并发编程实战:第二章----线程安全性
一个对象是否需要是线程安全的取决于它是否被多个线程访问. 当多个线程访问同一个可变状态量时如果没有使用正确的同步规则,就有可能出错.解决办法: 不在线程之间共享该变量 将状态变量修改为不可变的 在访问 ...
- Java并发编程实战 第2章 线程安全性
编写线程安全的 代码,核心在与对共享的和可变的对象的状态的访问. 如果多个线程访问一个可变的对象时没有使用同步,那么就会出现错误.在这种情况下,有3中方式可以修复这个问题: 不在线程之间共享该状态变量 ...
- Java并发编程实战(3)- 互斥锁
我们在这篇文章中主要讨论如何使用互斥锁来解决并发编程中的原子性问题. 目录 概述 互斥锁模型 互斥锁简易模型 互斥锁改进模型 Java世界中的互斥锁 synchronized中的锁和锁对象 synch ...
- java并发编程实战《三》互斥锁(上)
互斥锁(上):解决原子性问题 原子性问题的源头是线程切换,操作系统做线程切换是依赖 CPU 中断的,所以禁止 CPU 发生中断就能够禁止线程切换. 在早期单核 CPU 时代,这个方案的确是可行的,而且 ...
随机推荐
- C#使用WebService
一.新建webservice 新建项目→asp.net Web服务应用程序 或者在现有项目中 点击右键 新建web服务程序asmx 只要在webservice类里面 的方法 标注为[WebMethod ...
- 使用用WCF中的双工(Duplex)模式将广告图片推送到每个Winform客户端机子上
参考资料地址:http://www.cnblogs.com/server126/archive/2011/08/11/2134942.html 代码实现: WCF宿主(服务端) IServices.c ...
- Java File文件操作 创建文件\目录,删除文件\目录
Java手册 java.io 类 File java.lang.Object java.io.File 所有已实现的接口: Serializable, Comparable<File> p ...
- sql之强制索引
1.今天我遇到一个问题,在处理百万级数据查询的时候,一般查询会很慢. 2.第一时间想到是建立联合索引,但是数据库存在多条索引的情况下,索引的执行是全部执行. 3.所以这里要按照特定的索引执行,就必须使 ...
- java HttpClient 获取页面Cookie信息
HttpClient client = new HttpClient(); GetMethod get=new GetMethod("http://www.baidu.com"); ...
- 【UVALive】2965 Jurassic Remains(中途相遇法)
题目 传送门:QWQ 分析 太喵了~~~~~ 还有中途相遇法这种东西的. 嗯 以后可以优化一些暴力 详情左转蓝书P58 (但可能我OI生涯中都遇不到正解是这个的题把...... 代码 #include ...
- ES6系列_6之新增的数组知识
1.JSON数组格式转换 JSON的数组格式就是为了前端快速的把JSON转换成数组的一种格式,json数组格式如下: let json = { '0': '男', '1': '女', length:3 ...
- FCCMBBTN.RES
[ilink32 Error] Error: Unable to open file 'FCCMBBTN.RES' 用到了fc控件 添加路径到LibPath即可. 1st\1stClassStudio ...
- xdebug php
sudo apt-get install php5-dev php5-cli #其中php5-dev为了安装xdebug所以必须安装. sudo apt-get install php5-xsl #X ...
- MVC-READ2
框架设计模式 契约式设计.元编程.元数据驱动设计.管道模型.远程代理模式.提供程序模型: