转载请注明原文地址: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. java把指定文字输出为图片流,支持文字换行

    public class IamgeUtils { private static final int WIDTH = 350; private static final int HEIGHT = 10 ...

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

    矩形按钮是我们很常用的控件,让其拥有5.0动效必须自定义控件.本文讲解的控件是参考: https://github.com/shark0017/MaterialDesignLibrary 一.放入布局 ...

  3. java 生成zip文件并导出

    总结一下,关于Java下载zip文件并导出的方法,浏览器导出. String downloadName = "下载文件名称.zip"; downloadName = Browser ...

  4. 几种常见的JavaScript混淆和反混淆工具分析实战

    几种常见的JavaScript混淆和反混淆工具分析实战 xiaix2016-03-05+8共1195751人围观 ,发现 5 个不明物体WEB安全 信息安全常被描述成一场军备竞赛,白帽与黑帽,渗透测试 ...

  5. Set a Room Mailbox to Show Details of a Meeting in its Calendar – Office 365

    You may notice that meetings with a ‘Room’ mailbox will by default only show a “Busy” status. Many, ...

  6. 从头认识Spring-2.1 自己主动装配(2)-byType(2)

    为了解决配置文件中面出现多个同类型的Bean而byType无法匹配的问题.引入了primary和autowire-candidate属性. 1.primary 因为全部bean默认的primary都是 ...

  7. iOS: 获取UITableViewCell上添加的子控件对应的cell

    一.简单介绍 UITableViewCell是UITableView的核心部分,我们在开发中因为功能的扩展经常需要自定义,以便在其上面添加子控件,例如button.label等.添加后获取这些子控件的 ...

  8. [转]QT QDateTime类、QTimer类

    QDateTime类,头文件#include <QDateTime> 可以使用QDateTime类来获得系统时间.通过QDateTime::currentDateTime()来获取本地系统 ...

  9. Maven镜像更换为阿里云中央仓库

    前言 maven仓库默认在国外,使用难免很慢,尤其是下载依赖的时候,换为国内镜像,让你感受飞一般的感觉.国内支持maven镜像的有阿里云,开源中国等,这里换为阿里云的. 更换 修改maven配置文件s ...

  10. windows下mysql忘记root密码的解决办法

    今天早上 一朋友说自己的mysql 忘记root密码了 让我帮忙给看看,因为没有接触过mysql 所以从网上找了一下信息经我亲身实践  已经成功!mysql版本是5.1以下是从网上找的信息: 1. 首 ...