转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543947.html 

我们知道,线程安全问题需要通过线程之间的同步来解决,而同步大多使用syncrhoized关键字,简单方便。但是syncrhoized功能上较单一,为此,concurrent包为我们提供了额外的几种同步控制工具,让我们可以根据不同的同步需求更加灵活地选择同步工具。

一:ReentrantLock(重入锁)

ReentrantLock具有可重入、可中断、可限时申请、可公平获取等特点。

它的使用很简单:1:创建一个reentrantlock对象;2:在需要同步控制的代码块的起始处用 lock.lock() 加锁;3:在退出同步控制块处  lock.unlock() 解锁。

1)可重入

ReentrantLock可以重复获得同一把锁,即:在一个线程中,一个reentrantlock对象可以重复调用 lock() 申请这个锁对象进行加锁。

    我们知道。如果一个线程申请同步锁时,如果锁被占用了就会导致阻塞,等待请求的锁释放,若是请求的锁刚好是自己以及在使用的锁呢?难道也要导致阻塞吗?可重入性就是为了解决这个问题,若当前线程请求的锁是自己已获得的锁,则使锁的获取计数器+1而已,不会自己阻塞自己,线程继续照常执行。

但是可重入性也要求了,一个线程请求了多少次同一个锁,那么就要相应地在结束时释放多少次。

lock.lock();
lock.lock();
try
{
i++; }
finally
{
lock.unlock();
lock.unlock();
}

2)可中断

如果有两个线程,一个在lock1.lock()后申请了lock2.lock(),一个在lock2.lock()后申请了lock1.lock(),启动这两个线程。这两个线程都在等待对方释放掉已申请的lock,好让自己获得第二个lock而进行下去,这样的话就会导致死锁。我们知道死锁是由于资源请求存在环路导致的,只要打破这个环路即可让大部分请求得到满足,打破就是我们说的——中断。我们可以通过中断其中一个线程,使其让出所占用的资源(已获得的lock),则另一个线程即可获得两个lock而得以继续进行下去。

reentrantlock的可中断锁是通过 lockInterruptibly() 获取的,而不是普通的 lock()方法。

public static ReentrantLock lock1 = new ReentrantLock();

lock1.lockInterruptibly();
            

我们怎么知道死锁并解决呢?这需要用到ThreadMXBean(Java虚拟机线程管理接口)中提供的一系列方法,我们可以通过 ManagementFactory .getThreadMXBean();来获得一个线程管理接口的实现类,里面实现了ThreadMXBean中的线程管理方法,罗列如下:

方法摘要
 ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) 
          返回所有活动线程的线程信息,并带有堆栈跟踪和同步信息。
 long[] findDeadlockedThreads() 
          查找因为等待获得对象监视器或可拥有同步器而处于死锁状态的线程循环。
 long[] findMonitorDeadlockedThreads() 
          找到处于死锁状态(等待获取对象监视器)的线程的周期。
 long[] getAllThreadIds() 
          返回活动线程 ID。
 long getCurrentThreadCpuTime() 
          返回当前线程的总 CPU 时间(以毫微秒为单位)。
 long getCurrentThreadUserTime() 
          返回当前线程在用户模式中执行的 CPU 时间(以毫微秒为单位)。
 int getDaemonThreadCount() 
          返回活动守护线程的当前数目。
 int getPeakThreadCount() 
          返回自从 Java 虚拟机启动或峰值重置以来峰值活动线程计数。
 int getThreadCount() 
          返回活动线程的当前数目,包括守护线程和非守护线程。
 long getThreadCpuTime(long id) 
          返回指定 ID 的线程的总 CPU 时间(以毫微秒为单位)。
 ThreadInfo getThreadInfo(long id) 
          返回指定 id 的不具有堆栈跟踪的线程的线程信息。
 ThreadInfo[] getThreadInfo(long[] ids) 
          返回其 ID 在输出数组 ids 中的每个线程的线程信息,这些线程不具有堆栈跟踪。
 ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) 
          返回每个线程的线程信息,线程 ID 位于输入数组 ids 中,带有堆栈跟踪和同步信息。
 ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) 
          返回其 ID 在输入数组 ids 中的每个线程的线程信息,并带有指定堆栈追踪元素数的堆栈追踪。
 ThreadInfo getThreadInfo(long id, int maxDepth) 
          返回指定 id 的线程的线程信息,并带有指定堆栈追踪元素数的堆栈追踪。
 long getThreadUserTime(long id) 
          返回指定 ID 的线程在用户模式中执行的 CPU 时间(以毫微秒为单位)。
 long getTotalStartedThreadCount() 
          返回自从 Java 虚拟机启动以来创建和启动的线程总数目。
 boolean isCurrentThreadCpuTimeSupported() 
          测试 Java 虚拟机是否支持当前线程的 CPU 时间测量。
 boolean isObjectMonitorUsageSupported() 
          测试 Java 虚拟机是否支持使用对象监视器的监视。
 boolean isSynchronizerUsageSupported() 
          测试 Java 虚拟机是否支持使用可拥有同步器的监视。
 boolean isThreadContentionMonitoringEnabled() 
          测试是否启用了线程争用监视。
 boolean isThreadContentionMonitoringSupported() 
          测试 Java 虚拟机是否支持线程争用监视。
 boolean isThreadCpuTimeEnabled() 
          测试是否启用了线程 CPU 时间测量。
 boolean isThreadCpuTimeSupported() 
          测试 Java 虚拟机实现是否支持任何线程的 CPU 时间测量。
 void resetPeakThreadCount() 
          将峰值线程计数重置为当前活动线程的数量。
 void setThreadContentionMonitoringEnabled(boolean enable) 
          启用或禁用线程争用监视。
 void setThreadCpuTimeEnabled(boolean enable) 
          启用或禁用线程 CPU 时间测量。

从上面我们可以看到,通过ThreadMXBean我们可以获取虚拟机当前运行的所以线程的信息,包括 线程ID、存活的线程、死锁的线程等等信息。

所以,我们可以通过ThreadMXBean获取到由reentrantlock的lockInterruptibly()导致的死锁的随便一个线程的ID,然后通过 线程的interrupt() 方法自动中断自己,就可以使得死锁环中其他线程得以顺利执行。

3)可限时申请锁

reentrantlock对象可以限时申请获得锁,如果在限定时间内没能获取则放弃申请,在没锁的情况下执行代码(此时是不同步进行,线程不安全)。这样就不会由于申请被占用的锁而阻塞线程。

限时申请锁是通过 lock.trylock(num,unit)实现的,unit是时间单元,可以选择秒、分钟、小时、天等,num是数量,指定有多少个时间单元时间用来尝试获得锁。

public static ReentrantLock lock = new ReentrantLock();

lock.tryLock(5, TimeUnit.SECONDS);
            

4)可公平获取

一般的锁不是公平的,不会说先申请的线程就先获得锁,这样容易使得某一个线程一直处于申请获得锁的状态,即——饥饿。

ReentrantLock可以在创建时通过构造参数指定是不是公平锁,当作为公平锁创建时,申请获得该锁的线程们将严格按照“先申请先获得”的顺序来使用该锁。

public ReentrantLock(boolean fair) 

public static ReentrantLock fairLock = new ReentrantLock(true);

Java多线程之ReentrantLock重入锁简介与使用教程的更多相关文章

  1. java并发系列(三)-----ReentrantLock(重入锁)功能详解和应用演示

    1. ReentrantLock简介 jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock.虽然在性能上ReentrantLock和synchronize ...

  2. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  3. java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)

    1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...

  4. ReentrantLock(重入锁)以及公平性

    ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...

  5. 从源码角度彻底理解ReentrantLock(重入锁)

    目录 1.前言 2.AbstractQueuedSynchronizer介绍 2.1 AQS是构建同步组件的基础 2.2 AQS的内部结构(ReentrantLock的语境下) 3 非公平模式加锁流程 ...

  6. ReentrantLock(重入锁)的源码解析

    转自:从源码角度彻底理解ReentrantLock(重入锁)](https://www.cnblogs.com/takumicx/p/9402021.html)) 公平锁内部是FairSync,非公平 ...

  7. Java多线程之ReentrantLock与Condition

    一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...

  8. ReentrantLock 重入锁(下)

    前沿:       ReentrantLock 是java重入锁一种实现,在java中我们通常使用ReentrantLock 和 synchronized来实现锁功能,本篇通过例子来理解下Reentr ...

  9. java多线程之ReentrantLock

    前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...

随机推荐

  1. .NET零基础入门05:委托与事件

    一:前言 本小节,我们需要停一停我们的小游戏开发,虽然它现在还不完美,还很简单,甚至还有BUG.但是,为了更好的理解C#,现在到了该深入了解一些基础知识的时候了. 当然,实际上,本小节内容对于零基础入 ...

  2. SVG.js Marker标记和自定义标签

    一.SVG.Marker 添加标记 SVG.Marker 标记可以被添加到一个线,折线的各点,多边形和路径.有三种类型的标记:开始,中间和结束.如果开始表示第一个点,则结束中间的最后一点和中间点. v ...

  3. pssh,pdsh,mussh,cssh,dsh运维工具介绍

    pssh 1 安装:#wget http://peak.telecommunity.com/dist/ez_setup.pypython ez_setup.py#wget http://paralle ...

  4. JavaScript:Events

    ylbtech-JavaScript:Events 1.返回顶部 JavaScript 事件参考手册 事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行. 事件句柄 HTML 4.0 的新 ...

  5. IIS6 Gzip 网页GZIP压缩(转)

    现在主流浏览器基本都支持 Gzip 压缩,因此这也成了 WebServer 优化策略的一种常规手段.启用压缩后能有效减少网页传输数据大小,使得有限带宽能提供更多的请求,并在一定程度上提高了网页 &qu ...

  6. vue-自定义组件传值

    项目中,我们经常会遇到自定义组件传值的问题,方法很多种,但是原理很简单,下述文档总结实际项目中使用的传值方式. 父组件传递给子组件某一值,子组件内会修改该值,然后父组件需要获取新值 ​ 在 Vue 中 ...

  7. CentOS6 安装并破解Jira 7

    CentOS6 安装并破解Jira 7 JIRA软件是为您的软件团队的每个成员构建的,用来规划,跟踪和发布优秀的软件. https://confluence.atlassian.... 最低硬件要求及 ...

  8. Tag Archives: 海明距离

    在前一篇文章 <海量数据相似度计算之simhash和海明距离> 介绍了simhash的原理,大家应该感觉到了算法的魅力.但是随着业务的增长 simhash的数据也会暴增,如果一天100w, ...

  9. THINKPHP 验证码不显示

    最近同事将我之前使用Thinkphp做的一个项目从香港服务器迁移到国内,但却遇到了图片验证码不显示的问题 但我确认了以下可能的问题后还是没有解决 PHP是否已经安装GD库支持: 输出之前是否有任何的输 ...

  10. Eclipse Maven项目报错3之找不到配置文件spring-servlet-context.xml

    一.具体错误如下图所示 根据文字提示可以看出是这个文件找不到,但是我去项目的这个目录找了,这个文件确实存在,那么是什么问题呢 二.解决问题 原因分析(来自网上) 代码编译的过程,是一个自动生成相应编译 ...