转自:http://ifeve.com/java_lock_see4/
锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) 。这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及。本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解惑。
本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock。可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。
在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁
下面是使用实例
01 |
public class Test implements Runnable{
|
02 |
03 |
public synchronized void get(){
|
04 |
System.out.println(Thread.currentThread().getId());
|
05 |
set();
|
06 |
}
|
07 |
08 |
public synchronized void set(){
|
09 |
System.out.println(Thread.currentThread().getId());
|
10 |
}
|
11 |
12 |
@Override
|
13 |
public void run() {
|
14 |
get();
|
15 |
}
|
16 |
public static void main(String[] args) {
|
17 |
Test ss= new Test();
|
18 |
new Thread(ss).start();
|
19 |
new Thread(ss).start();
|
20 |
new Thread(ss).start();
|
21 |
}
|
22 |
} |
01 |
public class Test implements Runnable {
|
02 |
ReentrantLock lock = new ReentrantLock();
|
03 |
04 |
public void get() {
|
05 |
lock.lock();
|
06 |
System.out.println(Thread.currentThread().getId());
|
07 |
set();
|
08 |
lock.unlock();
|
09 |
}
|
10 |
11 |
public void set() {
|
12 |
lock.lock();
|
13 |
System.out.println(Thread.currentThread().getId());
|
14 |
lock.unlock();
|
15 |
}
|
16 |
17 |
@Override
|
18 |
public void run() {
|
19 |
get();
|
20 |
}
|
21 |
22 |
public static void main(String[] args) {
|
23 |
Test ss = new Test();
|
24 |
new Thread(ss).start();
|
25 |
new Thread(ss).start();
|
26 |
new Thread(ss).start();
|
27 |
}
|
28 |
} |
两个例子最后的结果都是正确的,即 同一个线程id被连续输出两次。
结果如下:
Threadid: 8
Threadid: 8
Threadid: 10
Threadid: 10
Threadid: 9
Threadid: 9
可重入锁最大的作用是避免死锁
我们以自旋锁作为例子,
01 |
public class SpinLock {
|
02 |
private AtomicReference<Thread> owner = new AtomicReference<>();
|
03 |
public void lock(){
|
04 |
Thread current = Thread.currentThread();
|
05 |
while (!owner.compareAndSet( null , current)){
|
06 |
}
|
07 |
}
|
08 |
public void unlock (){
|
09 |
Thread current = Thread.currentThread();
|
10 |
owner.compareAndSet(current, null );
|
11 |
}
|
12 |
} |
对于自旋锁来说,
1、若有同一线程两调用lock() ,会导致第二次调用lock位置进行自旋,产生了死锁
说明这个锁并不是可重入的。(在lock函数内,应验证线程是否为已经获得锁的线程)
2、若1问题已经解决,当unlock()第一次调用时,就已经将锁释放了。实际上不应释放锁。
(采用计数次进行统计)
修改之后,如下:
01 |
public class SpinLock1 {
|
02 |
private AtomicReference<Thread> owner = new AtomicReference<>();
|
03 |
private int count = 0 ;
|
04 |
public void lock(){
|
05 |
Thread current = Thread.currentThread();
|
06 |
if (current==owner.get()) {
|
07 |
count++;
|
08 |
return ;
|
09 |
}
|
10 |
11 |
while (!owner.compareAndSet( null , current)){
|
12 |
13 |
}
|
14 |
}
|
15 |
public void unlock (){
|
16 |
Thread current = Thread.currentThread();
|
17 |
if (current==owner.get()){
|
18 |
if (count!= 0 ){
|
19 |
count--;
|
20 |
} else {
|
21 |
owner.compareAndSet(current, null );
|
22 |
}
|
23 |
24 |
}
|
25 |
26 |
}
|
27 |
} |
该自旋锁即为可重入锁。
相关推荐
今天小编就为大家分享一篇关于Java可重入锁的实现原理与应用场景,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
java手写可重入锁,对刚学锁的同学很有帮助,可以来下载互相学习一下。
https://blog.csdn.net/zhang5476499/article/details/83794711 【Java并发编程:自己动手写一把可重入锁】中用到的例子。
今天小编就为大家分享一篇关于Java源码解析之可重入锁ReentrantLock,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
各种锁汇总,乐观锁、悲观锁、分布式锁、可重入锁、互斥锁、读写锁、分段锁、类锁、行级锁等
java中的乐观锁与悲观锁,synchronized与ReentrantLock重入锁的说明与比较
java代码-证明synchronized可重入锁
主要介绍了Java锁之可重入锁介绍,可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响,需要的朋友可以参考下
redislock - 基于redis的分布式可重入锁
主要介绍了简单了解Java中的可重入锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
一、公平锁/非公平锁,二、可重入锁,三、独享锁/共享锁,四、互斥锁/读写锁
NULL 博文链接:https://zhaodengfeng1989.iteye.com/blog/2412430
之所以把这一章节叫做AQS简介而不是叫AQS详解,是因为已经有大神写过详解的文章Java并发之AQS详解,这篇文章对AQS的源码解析很透彻,博主读了之后受益匪浅,鉴于对原作者的尊重,所以如上附上原文的链接。...
• 熟悉Java多线程并发中线程基本方法,线程池,线程生命周期,熟悉Java锁中常见锁分类(乐观/悲观锁、自旋锁、独/共享锁、可重入锁、公平/非公平锁、分段锁、偏向锁,轻/重量级锁)和基本的锁升级策略
Java提供了多种类型的锁,包括 `synchronized` 块,可重入锁,读写锁和印章锁等。这些锁可以用来控制对共享资源的访问,从而保证数据一致性和线程安全。 在程序中使用锁需要注意锁定的粒度和时长,过大的锁粒度或...
摘要 从使用场景的角度出发来介绍对ReentrantLock的使用,相对来说容易理解一些。 场景1:如果发现该操作已经在执行中则不再执行(有状态执行) a、用在定时任务时,如果任务执行时间可能超过下次计划执行...
在JAVA中ReentrantLock 和synchronized 都是可重入锁; 重入锁ReentrantLock 相对来说是synchronized、Object.wait()和Object.notify()方法的替代品(或者说是增强版),在JDK5.0的早期版本,重入锁的性能远远好于...
3.同步器是面向锁的实现者,他简化了锁的实现方式,屏蔽了同步状态管理、线程排队、等待和唤醒等底层操作 4.同步器的设计是基于设计模式为:模板方法模式 AQS实现细节: 1.同步器依赖内部的同步队列-FIFO双向队列来...
主要介绍了Java并发编程之重入锁与读写锁,文中相关实例代码详细,测试可用,具有一定参考价值,需要的朋友可以了解下。