可重入和不可重入的概念是这样的:当一个线程获得了当前实例的锁,并进入方法A,这个线程在没有释放这把锁的时候,能否再次进入方法A呢?

  • 可重入锁:可以再次进入方法A,就是说在释放锁前此线程可以再次进入方法A(方法A递归)。
  • 不可重入锁(自旋锁):不可以再次进入方法A,也就是说获得锁进入方法A是此线程在释放锁钱唯一的一次进入方法A。

,具体区别查看可重入锁和不可重入锁区别

ReentrantLock,意思是“可重入锁”。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。下面通过一些实例看具体看一下如何使用ReentrantLock。

lock()的正确使用方法

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class MainLock {
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
final MainLock mainLock = new MainLock(); new Thread(new Runnable() {
@Override
public void run() {
mainLock.insert(Thread.currentThread());
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
mainLock.insert(Thread.currentThread());
}
}).start();
} public void insert(Thread thread){
lock.lock();//获取锁
try{
System.out.println(thread.getName() + "获取锁");
for(int i=0;i<5;i++){
System.out.println("------------------------" + thread.getName() + ":"+i+"------------------------");
}
}finally {
System.out.println(thread.getName() + "释放锁");
lock.unlock();//释放锁
}
}
}

结果:

Thread-0获取锁
------------------------Thread-0:0------------------------
------------------------Thread-0:1------------------------
------------------------Thread-0:2------------------------
------------------------Thread-0:3------------------------
------------------------Thread-0:4------------------------
Thread-0释放锁
Thread-1获取锁
------------------------Thread-1:0------------------------
------------------------Thread-1:1------------------------
------------------------Thread-1:2------------------------
------------------------Thread-1:3------------------------
------------------------Thread-1:4------------------------
Thread-1释放锁

tryLock()的使用方法

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class MainTryLock {
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
final MainTryLock mainTryLock = new MainTryLock(); new Thread(){
@Override
public void run() {
mainTryLock.insert(Thread.currentThread());
}
}.start(); new Thread(){
@Override
public void run() {
mainTryLock.insert(Thread.currentThread());
}
}.start();
} public void insert(Thread thread){
if(lock.tryLock()){
try{
System.out.println(thread.getName() + "获取锁");
for(int i=0;i<5;i++){
Thread.sleep(200);
}
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(thread.getName() + "释放锁");
lock.unlock();//释放锁
}
}else{
System.out.println(thread.getName()+"未获取到锁");
}
}
}

结果:

Thread-0获取锁
Thread-1未获取到锁
Thread-0释放锁

lockInterruptibly()响应中断的使用方法:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class MainLockInterruptibl {
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
MainLockInterruptibl test = new MainLockInterruptibl();
MyThread thread1 = new MyThread(test);
MyThread thread2 = new MyThread(test);
thread1.start();
thread2.start(); try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.interrupt();
} public void insert(Thread thread) throws InterruptedException{
lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
try {
System.out.println(thread.getName()+"得到了锁");
long startTime = System.currentTimeMillis();
for( int i=0;i<5;i++) {
TimeUnit.SECONDS.sleep(2);
}
} catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"执行finally");
lock.unlock();
System.out.println(thread.getName()+"释放了锁");
}
}
static class MyThread extends Thread {
private MainLockInterruptibl test = null;
public MyThread(MainLockInterruptibl test) {
this.test = test;
}
@Override
public void run() {
try {
test.insert(Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+"被中断");
}
}
}
}

结果:

Thread-0得到了锁
java.lang.InterruptedException
Thread-1被中断
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at com.concurrent.MainLockInterruptibl.insert(MainLockInterruptibl.java:25)
at com.concurrent.MainLockInterruptibl$MyThread.run(MainLockInterruptibl.java:48)
Thread-0执行finally
Thread-0释放了锁

源码地址:https://github.com/qjm201000/concurrent_reentrantLock.git

并发编程-concurrent指南-Lock-可重入锁(ReentrantLock)的更多相关文章

  1. 并发编程-concurrent指南-Lock

    既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题将在下面进行阐述.本文先从synchronized的缺陷讲起,然后再讲述java.util.concurr ...

  2. Java多线程——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...

  3. Java多线程系列——深入重入锁ReentrantLock

    简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...

  4. synchronized关键字,Lock接口以及可重入锁ReentrantLock

    多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...

  5. Java并发(九):重入锁 ReentrantLock

    先做总结: 1.为什么要用ReentrantLock? (1)ReentrantLock与synchronized具有相同的功能和内存语义: (2)synchronized是重量级锁,性能不好.Ree ...

  6. 轻松学习java可重入锁(ReentrantLock)的实现原理

    转载自https://blog.csdn.net/yanyan19880509/article/details/52345422,(做了一些补充) 前言 相信学过java的人都知道 synchroni ...

  7. 轻松学习java可重入锁(ReentrantLock)的实现原理(转 图解)

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

  8. Java 重入锁 ReentrantLock 原理分析

    1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...

  9. 17_重入锁ReentrantLock

    [概述] 重入锁可以完全代替synchronized关键字. 与synchronized相比,重入锁ReentrantLock有着显示的操作过程,即开发人员必须手动指定何时加锁,何时释放锁,所以重入锁 ...

  10. 重入锁 ReentrantLock (转)(学习记录)

    重入锁(ReentrantLock)是一种递归无阻塞的同步机制.以前一直认为它是synchronized的简单替代,而且实现机制也不相差太远.不过最近实践过程中发现它们之间还是有着天壤之别. 以下是官 ...

随机推荐

  1. C 语言main 函数终极探秘(&& 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行)

           所有的C程序必须定义一个称之为main的外部函数,这个函数是程序的入口,也就是当程序启动时所执行的第一个函数,当这个函数返回时,程序也将终止,并且这个函数的返回值被看成是程序成功或失败的 ...

  2. DataGridView动态添加新行的两种方法

    简单介绍如何为DataGridView控件动态添加新行的两种方 法: 方法一: int index=this.dataGridView1.Rows.Add();this.dataGridView1.R ...

  3. hexo-theme-next

    Hexo Next github主页:https://github.com/iissnan/hexo-theme-next 官网地址:http://theme-next.iissnan.com/ 一篇 ...

  4. python selenium chrome 测试

    #coding=utf-8 from selenium import webdriver from selenium.webdriver.common.keys import Keys from se ...

  5. 使用MultiByteToWideChar转换UTF8为GBK(UTF8在Windows的代码页是CP_UTF8)

    两个使用的函数: 1,UTF8转化为Unicode,inline为了编译后更快运行,老用到了,返回字符串为了使用链式表达式 inline WCHAR  *UTF8ToUnicode(const cha ...

  6. Linux下获取arm的交叉编译工具链

    转载请注明文章:Linux下获取arm的交叉编译工具链 出处:多客博图 这里介绍,Linux下获取arm的交叉编译工具链,比如arm-linux-gnueabihf-gcc.arm-linux-gne ...

  7. 【redis】redis的bind配置

    原文:[redis]redis的bind配置   在配置文件redis.conf中,默认的bind 接口是127.0.0.1,也就是本地回环地址.这样的话,访问redis服务只能通过本机的客户端连接, ...

  8. C#读取数据库内容并转换成xml文件

    OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\bi ...

  9. C#高性能大容量SOCKET并发(零):代码结构说明

    原文:C#高性能大容量SOCKET并发(零):代码结构说明 C#版完成端口具有以下特点: 连接在线管理(提供在线连接维护,连接会话管理,数据接收,连接断开等相关事件跟踪): 发送数据智能合并(组件会根 ...

  10. 邮件带附件和html格式

    1. 发送有附件的邮件需要添加一个附件类Attachment,这个附件可以为文件和图片: Attachment attach = new Attachment(“文件路径”");//文件 A ...