ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。ReenreantLock类的常用方法有:

ReentrantLock() : 创建一个ReentrantLock实例

ReentrantLock(boolean fair)  是否是公平锁,默认不是 【实际开发中 一般不开启公平】

lock() : 获得锁

unlock() : 释放锁

下面代码演示 ReentrantLock 实现的累加器

public class RentLack implements Runnable {
ReentrantLock lock = new ReentrantLock(); private int count = 0;
public int getCount()
{
return count;
}
@Override
public void run() { for (int i = 0; i < 10000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock(); //释放锁一定要写在finally里面
}
} } public static void main(String[] args) throws Exception {
RentLack rentLack = new RentLack();
Thread t1 = new Thread(rentLack);
Thread t2 = new Thread(rentLack);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(rentLack.getCount());
}
}

  

原理解析 ----------

说道ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS抽象的队列式的同步器),

AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch...。

-----深入了解AQS 请google相关信息

当我们调用 ReentrantLock lock = new ReentrantLock(); 看看具体是怎么做的?

 private final Sync sync;
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}  

可以看到,它调用是 上面两个类  他们的关系如下

ReentrantLock实现了Lock接口,获取锁是通过lock方法来实现的。

那当我们调用lock的时候,具体都做了什么呢? 这里只分析不公平方式

具体代码如下

   final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
} =======
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
} ==========
下来看看 非公平的方式的tryAcquire final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//state字段,在ReentrantLock中表示锁被持有的次数,它是一个volatile类型的整型值,因此对它的修改可以保证其他线程可以看到
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

  

执行流程如下

如果没有线程占有该资源,直接当前线程占有。

如果占用了,执行acquire(1)

  1. 调用tryAcquire()尝试直接去获取资源,如果成功则直接返回;
  2. 获取失败,则addWaiter()将该线程加入等待队列
  3. acquireQueued()使线程在等待队列中休息,有机会时(轮到自己,会被unpark())会去尝试获取资源。获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。

4.自我中断

在tryAcquire方法中可以看到,同一个线程获得锁以后可以多次重入,但是需要多次unlock哈。tryAcquire执行流程如下

1、首先判断锁有没有被持有,如果被持有,就判断持有锁的线程是不是当前线程,如果不是就啥也不做,返回获取失败,如果是就增加重入数,返回成功获取;

2、如果锁没有被任何线程持有(c==0),直接将当前线程设置为锁的持有者。

======================

总结:关于 synchronized , ReentrantLock 究竟用谁的问题?

synchronized 能解决的问题,ReentrantLock 都能解决  。

在性能上,Jdk8 对synchronized进行了优化,性能上差别不大。

java多线程系列6 synchronized 加强版 ReentrantLock的更多相关文章

  1. java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析

    java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...

  2. java多线程系列之 synchronized

    一.synchronized基本原理 java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁. ...

  3. Java多线程系列3 synchronized 关键词

    先来看一个线程安全的例子 ,两个线程对count进行累加,共累加10万次. public class AddTest { public static void main(String[] args) ...

  4. java多线程系列 目录

    Java多线程系列1 线程创建以及状态切换    Java多线程系列2 线程常见方法介绍    Java多线程系列3 synchronized 关键词    Java多线程系列4 线程交互(wait和 ...

  5. java多线程系列(四)---ReentrantLock的使用

    Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...

  6. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  7. Java多线程系列--“基础篇”04之 synchronized关键字

    概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...

  8. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  9. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

随机推荐

  1. python文件打开方式详解——a、a+、r+、w+区别

    出处: http://blog.csdn.net/ztf312/ 第一步 排除文件打开方式错误: r只读,r+读写,不创建 w新建只写,w+新建读写,二者都会将文件内容清零 (以w方式打开,不能读出. ...

  2. 对poi-excel导出的浅层理解

    上一篇对excel导入做了浅层的解释,本文将对导出再做浅层解释. 仍然是相同的套路,只不过是反过来而已. 反过来方向理论上本来是这样的:cell-->row-->sheet-->wo ...

  3. [UE4]Expandable Area可展开的区域

    一.Expandable Area控件分成头部和主体部分,头部和主体都是一个Named Slot,可以放置任何控件进去,点击头部会因此主体部分 1.如果勾选Size To Content,则收起的时候 ...

  4. sed -i命令详解

    [root@www ~]# sed [-nefr] [动作] 选项与参数: -n :使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上.但如果加 ...

  5. WM消息对应的Message消息中的Lparam和WParam

    具体的消息表示: 1. WM_PAINT消息,LOWORD(lParam)是客户区的宽,HIWORD(lParam)是客户区的高 2. 滚动条WM_VSCROLL或WM_HSCROLL消息,LOWOR ...

  6. java中Arrays的用法

    Arrays是针对数组的工具类,可以进行 排序,查找,复制填充等功能. 大大提高了开发人员的工作效率. 一 数组复制 与使用System.arraycopy进行数组复制类似的, Arrays提供了一个 ...

  7. 字符串String的API

      字符串的理解 1. 字符串的属性 str.length 2. 字符串的方法 charAt() charCodeAt() indexOf() lastIndexOf() slice() substr ...

  8. Maven私服(Nexus)资源上传下载

    1.settings.xml (向私服上传资源需要) <!-- Snapshot包的管理/Releases包的管理/第三方包管理--> <server> <id>l ...

  9. ActiveMQ(2)---ActiveMQ原理分析之消息发送

    持久化消息和非持久化消息的发送策略 消息同步发送和异步发送 ActiveMQ支持同步.异步两种发送模式将消息发送到broker上.同步发送过程中,发送者发送一条消息会阻塞直到broker反馈一个确认消 ...

  10. leetcode617

    这道题想了很久,并没有掌握思想,写了很多,也没有解决.先贴出思考的过程. class Solution { public: vector<TreeNode> v1; vector<T ...