转载请注明原文地址: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. redis实现秒杀demo

    代码 package com.prosay.redis; import java.util.List; import redis.clients.jedis.Jedis; import redis.c ...

  2. Material Designer的低版本兼容实现(八)—— Flat Button

       除了中规中矩的矩形按钮外,5.0中将按钮扁平化,产生了一个扁平按钮——Flat Button.这个按钮降低了很多存在感,主要用于在对话框,提示栏中.让整个界面减少层级.今天说的就是它的用法. 这 ...

  3. [Web 前端] 前端频道之团队维护、聚合、订阅

    cp from :https://blog.csdn.net/ivan820819/article/details/78885404 国内 腾讯 ISUX 腾讯全端 AlloyTeam 奇舞周刊 阿里 ...

  4. .Net AppDomain详解(一)

    AppDomain是CLR的运行单元,它可以加载Assembly.创建对象以及执行程序.AppDomain是CLR实现代码隔离的基本机制. 每一个AppDomain可以单独运行.停止:每个AppDom ...

  5. gNewSense 3.0 Beta 2 发布

    gNewSense 3.0 Beta 2 发布,下载地址:gnewsense-livecd-parkes-i386-3.0beta2.iso (1,078MB, MD5, torrent). 发行通知 ...

  6. 单页面应用SPA和多页面应用MPA

    单页面应用(SinglePage Web Application,SPA) 只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js.css等)仅需加载 ...

  7. XlsToOra

    ylbtech-Miscellaneos:XlsToOra 1. 返回顶部 在没有安装Oracle客户端而又需要将Excel数据导入Oracle表中时,XlsToOra可以方便快捷的达到你的目的.  ...

  8. matlib实现梯度下降法

    样本文件下载:ex2Data.zip ex2x.dat文件中是一些2-8岁孩子的年龄. ex2y.dat文件中是这些孩子相对应的体重. 我们尝试用批量梯度下降法,随机梯度下降法和小批量梯度下降法来对这 ...

  9. WinPcap权威指南(三):ARP协议

    ARP协议在局域网内使用的非常广泛,它的数据包类型分为请求包和答复包.Windows系统内部有一个缓冲区,保存了最近的ARP信息,可以在cmd下使用命令arp -a来显示目前的缓存,或者使用命令arp ...

  10. 记录Activity启动时间 ActivityLifecycleCallbacks

    ActivityStackManager 定义一个集合(Stack)保存所有还未销毁的 Activity public class ActivityStackManager { private Sta ...