ReentrantLock是重入锁,它与synchronized很像,它是synchronized的加强版,因为它具有一些synchronized没有的功能。
下面我们看看两者的区别:
synchronized具有一定的局限性:

  • 当线程尝试获取锁的时候,如果获取不到锁会一直阻塞;
  • 如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待;
  • 是非公平的。

而ReentrantLock实现了AQS,可以完成下列功能:

  • 可中断响应;
  • 锁申请等待限时;
  • 公平锁;
  • 与Condition一起使用,实现synchronized与wait/notify的功能。

引入几个概念:
提到ReentrantLock,我们不得不明白几个概念:

  • 可重入锁。可重入锁是指同一个线程可以多次获取同一把锁。ReentrantLock和synchronized都是可重入锁。
  • 可中断锁。可中断锁是指线程尝试获取锁的过程中,是否可以响应中断。synchronized是不可中断锁,ReentrantLock则提供了中断功能。
  • 公平锁与非公平锁。公平锁是指多个线程必须按顺序,不许插队。非公平锁允许插队。synchronized是非公平锁,而ReentrantLock的默认实现是非公平锁,但是也可以设置为公平锁。
  • CAS,在前面已经提到。

使用示例
具体用法通过简单代码通过代码演示:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo implements Runnable {
static ReentrantLock lock = new ReentrantLock();
static int count = 0; @Override
public void run() {
for (int i = 0; i < 10000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
} } public static void main(String[] args) {
ReentrantLockDemo r = new ReentrantLockDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
//结果输出:20000
}
}

通过ReentrantLock解决死锁问题:

import java.util.concurrent.locks.ReentrantLock;

public class KillDeadlockDemo implements Runnable {
static ReentrantLock lock1 = new ReentrantLock();
static ReentrantLock lock2 = new ReentrantLock();
int lock; public KillDeadlockDemo(int lock) {
super();
this.lock = lock;
} @Override
public void run() {
try {
if (lock == 1) {
lock1.lockInterruptibly();
Thread.sleep(500);
lock2.lockInterruptibly();
} else {
lock2.lockInterruptibly();
Thread.sleep(500);
lock1.lockInterruptibly();
}
} catch (InterruptedException e) {
} finally {
if (lock1.isHeldByCurrentThread()) {
lock1.unlock();
}
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getName() + "退出!");
} } public static void main(String[] args) {
KillDeadlockDemo kdd1 = new KillDeadlockDemo(1);
KillDeadlockDemo kdd2 = new KillDeadlockDemo(2);
Thread t1 = new Thread(kdd1);
Thread t2 = new Thread(kdd2);
t1.start();
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt();
/*
*结果输出:
*Thread-1退出!
*Thread-0退出!
*/
    }
}

使用 tryLock()或者tryLock(long timeout, TimeUtil unit) 方法进行一次限时的锁等待,也可以解决死锁问题:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; public class TryLockDemo implements Runnable {
static ReentrantLock lock = new ReentrantLock(); @Override
public void run() {
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
Thread.sleep(1100);
} else {
System.out.println(Thread.currentThread().getName() + "获取锁失败!释放");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} public static void main(String[] args) {
TryLockDemo td = new TryLockDemo();
Thread thread1 = new Thread(td);
Thread thread2 = new Thread(td);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//结果输出:Thread-1获取锁失败!释放
}
}

公平锁演示:

import java.util.concurrent.locks.ReentrantLock;

public class FairLockDemo implements Runnable {
static ReentrantLock lock = new ReentrantLock(true); @Override
public void run() {
while (true) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get lock");
Thread.sleep(1000);
} catch (InterruptedException e) {
} finally {
lock.unlock();
}
}
} public static void main(String[] args) {
FairLockDemo fld = new FairLockDemo();
Thread t1 = new Thread(fld);
Thread t2 = new Thread(fld);
Thread t3 = new Thread(fld);
t1.start();
t2.start();
t3.start();
/*
*Thread-0 get lock
*Thread-1 get lock
*Thread-2 get lock
*Thread-0 get lock
*Thread-1 get lock
*Thread-2 get lock
*..........
*/
}
}

浅谈原理

请转到:https://www.cnblogs.com/ericz2j/p/13445822.html



Java多线程_ReentrantLock的更多相关文章

  1. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  2. Java多线程基础知识篇

    这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...

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

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

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

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

  5. Java多线程--让主线程等待子线程执行完毕

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  6. Java多线程 2 线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  7. java 多线程 1 线程 进程

    Java多线程(一).多线程的基本概念和使用 2012-09-10 16:06 5108人阅读 评论(0) 收藏 举报  分类: javaSE综合知识点(14)  版权声明:本文为博主原创文章,未经博 ...

  8. 一起阅读《Java多线程编程核心技术》

    目录 第一章 Java多线程技能 (待续...)

  9. 第一章 Java多线程技能

    1.初步了解"进程"."线程"."多线程" 说到多线程,大多都会联系到"进程"和"线程".那么这两者 ...

随机推荐

  1. MacOS下Git安装及使用

    微信搜索"艺术行者",关注并回复关键词"git"获取Github安装包 上传的在线学习视频(黑马和传智双元,感谢) 微信搜索"艺术行者",关 ...

  2. P3565 由简单的树形dp 引入 长链刨分

    这道题感觉不太行 因为自己没想出来. 先说一下暴力吧,取三个点 让两两之间的距离相等怎么做呢,看起来是很复杂的样子的,但是仔细观察发现 答案出自一个点的儿子之间 或者儿子和父亲之间. 暴力枚举三个点然 ...

  3. log4j2 自动删除过期日志文件配置及实现原理解析

    日志文件自动删除功能必不可少,当然你可以让运维去做这事,只是这不地道.而日志组件是一个必备组件,让其多做一件删除的工作,无可厚非.本文就来探讨下 log4j 的日志文件自动删除实现吧. 0. 自动删除 ...

  4. 企业签名和TF签名哪个好?TF签名和企业签名怎么选?

    很多开发者在App无法上架Appstore,需要内测或者开放给苹果用户使用的时候,需要选择企业签名来帮助自己的App开放下载链接,给苹果用户使用.苹果企业签名的类型有很多,TF签名最近又很火爆,那么企 ...

  5. JDBC报错:Cannot find class: com.mysql.jdbc.Driver

    连接数据库的jar出现异常(通常报错:Cannot find class:com.mysql.jdbc.Drive), 问题:Connector的jar已经导入,还是出现 Cause: java.sq ...

  6. iOS开发多线程在实际项目中的运用

    实际项目开发中为了能够给用户更好的体验,有些延时操作我们都会放在子线程中进行. 今天我们就来聊聊多线程在实际项目中的运用. 我们先来看看多线程的基础知识: 1.多线程的原理: 同一时间,CPU只能处理 ...

  7. Serverless无服务器架构详解

    本文对Serverless架构的基础概念.具体产品.应用场景.工作原理进行详细解析. 基础概念 Serverless: 无服务器架构,即在无需管理服务器等底层资源的情况下完成应用的开发和运行,是云原生 ...

  8. MySQL回顾

    一. 对数据库的操作 1. 创建一个库 create database 库名 create database 库名 character set 编码 创建带有编码的 查看编码: 2. 删除一个库 dr ...

  9. leetcode 877. Stone Game 详解 -——动态规划

    原博客地址 https://blog.csdn.net/androidchanhao/article/details/81271077 题目链接 https://leetcode.com/proble ...

  10. MongoDB学习2:MongoDB的基本操作

    以下都是基于MongoShell进行操作 1.使用insert进行插入操作  示例: db.<集合>.insertOne(<JSON对象>) db.<集合>.ins ...