1 简介

  StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWriteLock的优化。在原先读写锁的基础上新增了一种叫乐观读(Optimistic Reading)的模式。该模式并不会加锁,所以不会阻塞线程,会有更高的吞吐量和更高的性能。

  ReentrantReadWriteLock介绍 :https://www.cnblogs.com/jthr/p/16179865.html

2 特性及注意事项

2.1 三种访问数据模式

  1)Writing(独占写锁):writeLock 方法会使线程阻塞等待独占访问,同一时刻有且只有一个写线程获取锁资源,功能和ReentrantReadWriteLock 的读类似,

  2)Reading(悲观读锁):readLock方法,读读共享,读写互斥。功能和ReentrantReadWriteLock的写锁类似

  3)Optimistic Reading(乐观读):Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式。

2.2 支持读写锁相互转换

  ReentrantReadWriteLock 当线程获取写锁后可以降级成读锁,但是反过来则不行。

  StampedLock提供了读锁和写锁相互转换的功能,使得该类支持更多的应用场景。

2.3 注意事项

  1)StampedLock是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)

  2)StampedLock 的悲观读锁和写锁都不支持条件变量(Condition),这个也需要注意。

  3)所有获取锁的方法,都返回一个邮戳(Stamp),Stamp为零表示获取失败,其余都表示成功;

  4)所有释放锁的方法,都需要一个邮戳(Stamp),这个Stamp必须是和成功获取锁时得到的Stamp一致;

  5)使用 StampedLock一定不要调用中断操作,即不要调用interrupt() 方法,如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly()和写锁writeLockInterruptibly()

StampedLockReentrantReadWriteLock效率高

  关键在于StampedLock 提供的乐观读,我们知道ReentrantReadWriteLock 支持多个线程同时获取读锁,但是当多个线程同时读的时候,所有的写线程都是阻塞的。

  StampedLock 的乐观读允许一个写线程获取写锁,所以不会导致所有写线程阻塞,也就是当读多写少的时候,写线程有机会获取写锁,减少了线程饥饿的问题,吞吐量大大提高。同时允许多个乐观读和一个先线程同时进入临界资源操作,那读取的数据可能是错的怎么办?

  是的,乐观读不能保证读取到的数据是最新的,所以将数据读取到局部变量的时候需要通过 lock.validate(stamp) 校验下是否被写线程修改过,若是修改过则需要上悲观读锁,再重新读取数据到局部变量。

  同时由于乐观读并不是锁,所以没有线程唤醒与阻塞导致的上下文切换,性能更好。

4 示例

public class StanpedlockLockTest1 {

    private double x, y;
private final StampedLock sl = new StampedLock(); //写锁-排他锁
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
} //下面看看乐观读锁案例
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead(); //获得一个乐观读锁
double currentX = x, currentY = y; //将两个字段读入本地局部变量
if (!sl.validate(stamp)) { //检查发出乐观读锁后同时是否有其他写锁发生?
stamp = sl.readLock(); //如果有,我们再次获得一个读悲观锁
try {
currentX = x; // 将两个字段读入本地局部变量
currentY = y; // 将两个字段读入本地局部变量
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
} //下面是悲观读锁转写锁
void moveIfAtOrigin(double newX, double newY) { // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock();
try {
while (true) {
long ws = sl.tryConvertToWriteLock(stamp); //将读锁转为写锁
if (ws != 0L) { //这是确认转为写锁是否成功
stamp = ws; //如果成功 替换票据
x = newX; //进行状态改变
y = newY; //进行状态改变
break;
}
else { //如果不能成功转换为写锁
sl.unlockRead(stamp); //我们显式释放读锁
stamp = sl.writeLock(); //显式直接进行写锁 然后再通过循环再试
}
}
} finally {
sl.unlock(stamp); //释放读锁或写锁
}
}
}

5 使用场景

  对于读多写少的高并发场景 StampedLock的性能很好,通过乐观读模式很好的解决了写线程“饥饿”的问题,我们可以使用StampedLock 来代替ReentrantReadWriteLock

线程基础知识15-StampedLock的更多相关文章

  1. Java__线程---基础知识全面实战---坦克大战系列为例

    今天想将自己去年自己编写的坦克大战的代码与大家分享一下,主要面向学习过java但对java运用并不是很熟悉的同学,该编程代码基本上涉及了java基础知识的各个方面,大家可以通过练习该程序对自己的jav ...

  2. java线程基础知识----线程与锁

    我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁. 1. 首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的 ...

  3. java线程基础知识----线程基础知识

    不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望 ...

  4. Windows核心编程 第六章 线程基础知识 (上)

    第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...

  5. Java并发之线程管理(线程基础知识)

    因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...

  6. Java线程基础知识(状态、共享与协作)

    1.基础概念 CPU核心数和线程数的关系 核心数:线程数=1:1 ;使用了超线程技术后---> 1:2 CPU时间片轮转机制 又称RR调度,会导致上下文切换 什么是进程和线程 进程:程序运行资源 ...

  7. java线程基础知识----java daemon线程

    java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程. 1.首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程 A. 用户线程: 用户线程可以简 ...

  8. java并发编程(一)----线程基础知识

    在任何的生产环境中我们都不可逃避并发这个问题,多线程作为并发问题的技术支持让我们不得不去了解.这一块知识就像一个大蛋糕一样等着我们去分享,抱着学习的心态,记录下自己对并发的认识. 1.线程的状态: 线 ...

  9. Java 线程基础知识

    前言 什么是线程?线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程 ID,当前指令指针 (PC),寄存器集合和堆栈组成.另外,线 ...

  10. Delphi线程基础知识

    参考http://blog.chinaunix.net/uid-10535208-id-2949323.html 一.概述 Delphi提供了好几种对象以方便进行多线程编程.多线程应用程序有以下几方面 ...

随机推荐

  1. 【笔记】CF1659E AND-MEX Walk 及相关

    题目传送门 位运算 设题目中序列 \(w_1,w_1\& w_2,w_1\& w_2\& w_3,\dots,w_1\& w_2\& \dots \& ...

  2. Python中Print方法

    1 number1 = int(input("请输入第一个数:")) 2 number2 = int(input("请输入第二个数:")) 3 4 # 方法一: ...

  3. Re:从零开始教你使用 Sublime Text

    目录 Re:从零开始教你使用 Sublime Text 0.前言 0-0.关于我为什么要写这篇文章 0-1.关于这篇文章会讲什么 0-2.适用人群 0-4.其他 0-5.无用的统计 1.安装和基础功能 ...

  4. ATM分析

    # 查看余额功能 1.第一层直接调用查看余额的接口(传当前登录用户名) 2.第二层直接调用第三层数据查询的接口 3.第二层从用户字典中提取出用户余额返回给第一层展示 # 账户提现功能 1.第一层获取用 ...

  5. Qwt开发笔记(二):Qwt基础框架介绍、折线图介绍、折线图Demo以及代码详解

    前言   QWT开发笔记系列整理集合,这是目前使用最为广泛的Qt图表类(Qt的QWidget代码方向只有QtCharts,Qwt,QCustomPlot),使用多年,系统性的整理,本系列旨在系统解说并 ...

  6. 跳出foreach循环

    直接return false没用,需要用throw来跳出foreach 1 try { 2 this.categoryList.forEach((item, index) => { 3 if ( ...

  7. 为什么 Random.Shared 是线程安全的

    在多线程环境中使用 Random 类来生成伪随机数时,很容易出现线程安全问题.例如,当多个线程同时调用 Next 方法时,可能会出现种子被意外修改的情况,导致生成的伪随机数不符合预期. 为了避免这种情 ...

  8. 06.python闭包

    python闭包 什么样的函数是 闭包函数 ? 满足以下条件: 闭:外层函数嵌套了一个内层函数. 包:内层函数调用外层函数命名空间内的名字. 举例如下: def out_func(): # 外层函数 ...

  9. des_招标

    网站 aHR0cHM6Ly9jdGJwc3AuY29tLyMv 翻到第二页,加载了一个2,并且返回的都是加密的数据  点到initiator,可以看到发送的Axios请求,尝试全局搜索intercep ...

  10. python 集合常用操作

    集合的特性 无序.不重复.可迭代 常用api 创建一个集合 需要显式地使用set()方法来声明,如果使用字面量{}来声明解析器会认为这是一个字典. add() 往集合中添加一个元素 demo = se ...