博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lock重入锁
阅读量:4292 次
发布时间:2019-05-27

本文共 2126 字,大约阅读时间需要 7 分钟。

前言

在并发编程中有两个核心问题, 一个是互斥另一个是同步。在java sdk并发包中,lock就是解决互斥问题,conditon就是解决同步问题。

Lock

lock有三个重要的特性:

  1. 能够响应中断: 线程在没有获取锁的时候,进入阻塞状态。我们能够给进入阻塞状态的线程发送信号,重新唤醒它。
  2. 支持超时: 在无法获取锁的时候,就等待一定的时间。超时就自动返回。
  3. 非阻塞的获取锁:如果无法获取锁就马上返回。
    以下为它的API
// 支持中断的 APIvoid lockInterruptibly()   throws InterruptedException;// 支持超时的 APIboolean tryLock(long time, TimeUnit unit)   throws InterruptedException;// 支持非阻塞获取锁的 APIboolean tryLock();

lock–内存可见性问题

可以先看代码

class X {  private final Lock rtl =  new ReentrantLock();  int value;  public void addOne() {    // 获取锁    rtl.lock();      try {      value+=1;    } finally {      // 保证锁能释放      rtl.unlock();    }  }}

这段代码,如果T1线程将value改为1 那么t2线程在执行的时候能够看见吗?

答案是肯定的。
它是利用了volatile相关的happes-before规则。java sdk里面的ReentrantLock,内部持有一个volatile的成员变量state,获取锁的时候,会读写 state的值;解锁的时候,也会读写state,在执行value+=1之后,又读写了一次volatile变量state。根据相关的Happens-before规则:

  1. 顺序性执行: 对于线程T1, value+=1 Happens-before释放锁的操作unlock()。
  2. volatile变量规则: 由于state= 1 会先读取state,所以线程T1的unlock() 操作Happens-before()线程T2的lock()操作。
  3. 传递性规则:线程T1的value+=1 Happens-Before线程T2的lock()操作。
class SampleLock {  volatile int state;  // 加锁  lock() {    // 省略代码无数    state = 1;  }  // 解锁  unlock() {    // 省略代码无数    state = 0;  }}

lock—重入锁

ReentrantLock,指的是线程可以重复获取同一把锁。例如下面的代码,当线程T1执行到1处时,已经获取到了锁rtl,当在1处调用get()方法时,会在2处再次对锁rtl执行加锁操作。如果锁rtl是可重入的,那么线程T1可以再次加锁成功。如果锁rtl是不可重入的,那么线程T1此时会被阻塞。

class X {  private final Lock rtl =  new ReentrantLock();  int value;  public int get() {    // 获取锁    rtl.lock();         ②    try {      return value;    } finally {      // 保证锁能释放      rtl.unlock();    }  }  public void addOne() {    // 获取锁    rtl.lock();      try {      value = 1 + get(); ①    } finally {      // 保证锁能释放      rtl.unlock();    }  }}

LOCK公平锁与非公平锁

ReentrantLock有两个构造方法。一个是无参构造,一个是传入fair。fair参数代表的是锁的公平策略,如果传入 true就表示需要构造一个公平锁,反之则表示构造一个非公平锁。

// 无参构造函数:默认非公平锁public ReentrantLock() {    sync = new NonfairSync();}// 根据公平策略参数创建锁public ReentrantLock(boolean fair){    sync = fair ? new FairSync()                 : new NonfairSync();}

公平锁就是先等待先唤醒,非公平锁是随机唤醒。

锁的使用经验

  1. 永远只在更新对象的成员变量时加锁
  2. 永远只在访问可变的成员变量
  3. 永远不在调用其他对象的方法时加锁

这三条中最后一条主要是担心在调用慢方法,如长时间IO或者业务复杂。 也会担心其他方法里面本身有锁,在调用的时候加锁会出现双重锁, 容易导致死锁。

转载地址:http://bnkws.baihongyu.com/

你可能感兴趣的文章
海龟交易法则08_风险与资金管理
查看>>
海龟交易法则09_海龟式积木
查看>>
海龟交易法则10_通用积木
查看>>
海龟交易法则14_掌控心魔
查看>>
海龟交易法则15_万事俱备
查看>>
海龟交易法则16_附原版海龟交易法则
查看>>
克罗谈投资策略01_期货交易中的墨菲法则
查看>>
克罗谈投资策略02_赢家和输家
查看>>
克罗谈投资策略03_你所期望的赌博方式
查看>>
克罗谈投资策略04_感觉与现实
查看>>
通向财务自由之路01_导读
查看>>
通向财务自由之路02_成功的决定因素:你
查看>>
中低频量化交易策略研发01_引言
查看>>
中低频量化交易策略研发06_推进的择时策略
查看>>
史丹·温斯坦称傲牛熊市的秘密
查看>>
期货市场技术分析01_理论基础
查看>>
期货市场技术分析02_趋势的基本概念
查看>>
期货市场技术分析03_主要反转形态
查看>>
期货市场技术分析04_持续形态
查看>>
期货市场技术分析05_交易量和持仓兴趣
查看>>