import java.util.concurrent.locks.ReentrantLock;

/**
* 重入锁 ReenterLock 一个线程允许连续获得同一把锁,注意:必须释放相同次数,释放次数多,会异常,少了相当于线程还持有这个锁,其他线程无法进入临界区
* 需要手动指定何时加锁何时释放锁
*
ReenterLock几个重要方法:
- lock():获得锁,如果锁已经被占用,则等待
- lockInterruptibly():获得锁,但优先响应中断
- tryLock():尝试获得锁,成功返回true,失败返回false,该方法不等待,立即返回
- tryLock(long time,TimeUnit unit):在给定时间内尝试获得锁
- unlock():释放锁
*/
public class ReentrantLockDemo implements Runnable{
public static Integer i = 0;
public static ReentrantLock lock = new ReentrantLock(); @Override
public void run() {
for (int j = 0; j < 10000000; j++) {
lock.lock();
try {
i++;
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException{
ReentrantLockDemo r = new ReentrantLockDemo();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r);
thread1.start();thread2.start();
thread1.join();thread2.join();
System.out.println(i);//20000000
}
}

中断处理

import java.util.concurrent.locks.ReentrantLock;

/**
* 避免死锁
* 重入锁的中断处理能力
*/
public class IntLock implements Runnable{
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public IntLock(int lock) {
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(); //22行
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
//检查当前线程是否拥有该锁
if (lock1.isHeldByCurrentThread()) lock1.unlock();
if (lock2.isHeldByCurrentThread()) lock2.unlock();
System.out.println(Thread.currentThread().getId()+":线程退出");
}
}
public static void main(String[] args) throws InterruptedException{
IntLock i1 = new IntLock(1);
IntLock i2 = new IntLock(2);
Thread t1 = new Thread(i1);
Thread t2 = new Thread(i2);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt(); //中断t2 ,t2放弃对lock1的申请,同时释放已获得的lock2
//java.lang.InterruptedException
// 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.combat.IntLock.run(IntLock.java:22)
// at java.lang.Thread.run(Thread.java:748)
//10:线程退出
//9:线程退出
}
}

限时等待

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; /**
* 限时等待锁
*/
public class TimeLockDemo implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)){ //等待时间,计时单位
Thread.sleep(6000);
}else {
System.out.println("get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread())lock.unlock();
}
}
public static void main(String[] args){
TimeLockDemo demo = new TimeLockDemo();
Thread t1 = new Thread(demo);
Thread t2 = new Thread(demo);
t1.start();
t2.start();
}
//get lock failed
//由于占用锁的线程为6秒,另一个线程无法在5秒的等待时间内获得锁,因此请求锁失败
}
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; /**
* tryLock
* 限时等待锁 无参数 如果锁被其他线程占用,则当前线程不会进行等待,而是立即返回false,不会引起线程等待
*/
public class TimeLockDemo2 implements Runnable{
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;
public TimeLockDemo2(int lock) {
this.lock = lock;
}
@Override
public void run() {
if (lock == 1){
while (true){
if (lock1.tryLock()){
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock2.tryLock()){
try {
System.out.println(Thread.currentThread().getId()+":my job done");
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
}else {
while (true){
if (lock2.tryLock()){
try {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (lock1.tryLock()){
try {
System.out.println(Thread.currentThread().getId()+":my job done");
return;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
}
}
}
public static void main(String[] args){
TimeLockDemo2 r1 = new TimeLockDemo2(1);
TimeLockDemo2 r2 = new TimeLockDemo2(1);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
//9:my job done
//10:my job done
}

公平锁

import java.util.concurrent.locks.ReentrantLock;

/**
* 公平锁
* synchronized产生的锁是非公平锁
* 重入锁可以设置公平性
*/
public class FairLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock(true);
@Override
public void run() {
while (true){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"获得锁");
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException{
FairLock lock = new FairLock();
Thread t1 = new Thread(lock, "thread_t1");
Thread t2 = new Thread(lock, "thread_t2");
t1.start();
t2.start();
}
//...
//thread_t2获得锁
//thread_t1获得锁
//thread_t2获得锁
//thread_t1获得锁
//thread_t2获得锁
//...
//两个线程基本交替获得锁 //而非公平锁,一个线程会倾向于再次获得已持有的锁,这种分配方式是高效的,但无公平性可言
}

20.ReenterLock重入锁的更多相关文章

  1. AQS学习(二) AQS互斥模式与ReenterLock可重入锁原理解析

    1. MyAQS介绍    在这个系列博客中,我们会参考着jdk的AbstractQueuedLongSynchronizer,从零开始自己动手实现一个AQS(MyAQS).通过模仿,自己造轮子来学习 ...

  2. 可重入锁(good)

    可重入锁,也叫做递归锁,是指在一个线程中可以多次获取同一把锁,比如:一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法[即可重入],而无需重新获得锁: ...

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

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

  4. 浅谈Java中的锁:Synchronized、重入锁、读写锁

    Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...

  5. synchronized 是可重入锁吗?为什么?

    什么是可重入锁? 关于什么是可重入锁,我们先来看一段维基百科的定义. 若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(re ...

  6. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

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

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

  8. synchronized的功能拓展:重入锁(读书笔记)

     重入锁可以完全代替synchronized关键字.在JDK5.0的早期版本中,重入锁的性能远远好于synchronized,但是从JDK6.0开始.JDK在synchronized上做了大量的优化. ...

  9. redis实现分布式锁需要考虑的因素以及可重入锁实现

    死锁 错误例子 解决方式  防止死锁 通过设置超时时间  不要使用setnx key   expire 20  不能保证原子性 如果setnx程序就挂了 没有执行expire就死锁了  reidis2 ...

随机推荐

  1. FreeBSD虚拟机——小折腾

    最近,突然想起来Linux了,因为前段时间接触了DOS命令,提高了自己的工作效率,这会想再温习下Linux的CLI,无奈windows下unix命令,水土不服,因此想尝试虚拟机,虚拟机软件无非vmwa ...

  2. tuple unpacking

    拆开Tuple lax_coordinates = (33.9425, -118.408056) latitude, longitude = lax_coordinates # tuple unpac ...

  3. nyoj 83:迷宫寻宝(二)(计算几何)

    题目链接 枚举所有墙的2n个端点与宝物的位置作为一条线段(墙的端点必定与边界重合), 求出与之相交的最少线段数(判断线段相交时用跨立实验的方法),+1即为结果. #include<bits/st ...

  4. 线程join方法demo-模拟叫号看病

    package cn.chapter4.test5; public class SicknessDemo { /** * 模拟叫号看病 * @param args * * 思路:把普通号看病写在主线程 ...

  5. C# 私有字段前缀 _ 的设置(VS2019, .editorconfig)

    常量和静态只读字段大写 私有字段前缀 _ #### Naming styles #### # Naming rules dotnet_naming_rule.const_should_be_all_u ...

  6. 【HDU5306】【DTOJ2481】Gorgeous Sequence【线段树】

    题目大意:给你一个序列a,你有三个操作,0: x y t将a[x,y]和t取min:1:x y求a[x,y]的最大值:2:x y求a[x,y]的sum 题解:首先很明显就是线段树裸题,那么考虑如何维护 ...

  7. 处理警告:编码 GBK 的不可映射字符

    怎么处理警告:编码 GBK 的不可映射字符:javac -encoding UTF-8 XX.java使用-encoding参数指明编码方式: 或者 用记事本打开文件,然后另存为,选择ANSI编码,覆 ...

  8. excle里边的数据怎么导入oracle数据库

    方式一:(不正式) select出的列数与已经准备好的excle中的列数相同.select  xh,name from 表名 where xh = 'ghf' for update;  (查不到任何结 ...

  9. 高并发大流量专题---3、前端优化(减少HTTP请求次数)

    高并发大流量专题---3.前端优化(减少HTTP请求次数) 一.总结 一句话总结: 图片地图:使用<map><area></area></map>标签. ...

  10. sqlserver数据库里怎样设置datetime类型的小数位数为3位

    要用datetime2(7)这种类型!将7改为3就行了