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. go语言学习--处理map的无序输出

    最近工作中遇到了这样的一个场景,需要处理一个无限极分类的问题,对于数据结构的定义首先想到了,map,map[int]map[int]struct.通过两层map的定义归类parent_id和id的关系 ...

  2. TypeScript 模块系统

    https://www.cnblogs.com/niklai/p/5808789.html

  3. vlan划分

    1.vlan:虚拟局域网: 作用:划分广播域,抑制广播风暴: 2.vlan技术的优点: 有效控制广播域范围: 增强局域网的安全性: 灵活构建虚拟工作组: 3.vlan划分的方式: 基于端口: 基于MA ...

  4. js解决转义字符问题

    数据“\\s=7\\c=1\\j=1\\p=1”, 转义出来变成“\s=7\c=1\j=1\p=1” 结果:可以这样转换str=str.replace(/\\/g,'\\\\');

  5. Idea中运行项目时出现:未结束的字符串解决方案

    一般出现这种情况是编码不一致导致 解决办法: settings>file Encodings 编码设置成一致

  6. 调整iframe滚动条失效

    1:<iframe scrolling="auto" frameborder="0" src="' + add + '" style= ...

  7. HTML5-canvas1.0

    HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.<canvas> 标签只是图形容器,您必须使用脚本来绘制图形.你可以通过多种方 ...

  8. js 生成手机图片并保存到相册

    1.注意权限问题 2.调用HTML5+api 3.优化显示 4.注意兼容ios.Android

  9. 【Noip模拟 20160929】树林

    题目描述 现在有一片树林,小B很想知道,最少需要多少步能围绕树林走一圈,最后回到起点.他能上下左右走,也能走对角线格子. 土地被分成RR行CC列1≤R≤50,1≤C≤501≤R≤50,1≤C≤50,下 ...

  10. 吴裕雄 python深度学习与实践(7)

    import cv2 import numpy as np img = np.mat(np.zeros((,))) cv2.imshow("test",img) cv2.waitK ...