java 锁与可重入锁
来源:互联网 发布:linux ab压力测试 编辑:程序博客网 时间:2024/05/29 10:10
简单锁
在讲述简单锁的实现之前,我们先来看一个锁的应用例子:
public class Counter{ private Lock lock = new Lock(); private int count = 0; public int inc(){ lock.lock(); this.count++; lock.unlock(); return count; }}
上面的程序中,由于this.count++
这一操作分多步执行,在多线程环境中可能出现结果不符合预期的情况,这段代码称之为 临界区 ,所以需要使用lock来保证其原子性。
Lock的实现:
public class Lock{ private boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ //不用if,而用while,是为了防止假唤醒 wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); }}
说明:当isLocked为true时,调用lock()的线程在wait()阻塞。 为防止该线程虚假唤醒,程序会重新去检查isLocked条件。 如果isLocked为false,当前线程会退出while(isLocked)循环,并将isLocked设回true,让其它正在调用lock()方法的线程能够在Lock实例上加锁。当线程完成了临界区中的代码,就会调用unlock()。执行unlock()会重新将isLocked设置为false,并且唤醒 其中一个 处于等待状态的线程。
锁的可重入性
同样,先举例来说明锁的可重入性:
public class UnReentrant{ Lock lock = new Lock(); public void outer(){ lock.lock(); inner(); lock.unlock(); } public void inner(){ lock.lock(); //do something lock.unlock(); }}
outer中调用了inner,outer先锁住了lock,这样inner就不能再获取lock。其实调用outer的线程已经获取了lock锁,但是不能在inner中重复利用已经获取的锁资源,这种锁即称之为 不可重入 。通常也称为 自旋锁 。相对来说,可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。
可重入锁的基本原理
我们在上面的Lock基础上作一些修改:
public class Lock{ boolean isLocked = false; Thread lockedBy = null; int lockedCount = 0; public synchronized void lock() throws InterruptedException{ Thread callingThread = Thread.currentThread(); while(isLocked && lockedBy != callingThread){ wait(); } isLocked = true; lockedCount++; lockedBy = callingThread; } public synchronized void unlock(){ if(Thread.curentThread() == this.lockedBy){ lockedCount--; if(lockedCount == 0){ isLocked = false; notify(); } } }}
- lockBy:保存已经获得锁实例的线程,在lock()判断调用lock的线程是否已经获得当前锁实例,如果已经获得锁,则直接跳过while,无需等待。
- lockCount:记录同一个线程重复对一个锁对象加锁的次数。否则,一次unlock就会解除所有锁,即使这个锁实例已经加锁多次了。
自旋锁
发生在同一线程对锁的重复利用。
自旋锁代码如下:
对于自旋锁来说:
1、若有同一线程两次调用lock() ,会导致第二次调用lock位置进行自旋(意思是第一次调用已经获得锁了,则第二次调用无法获得这个锁),产生了死锁
说明这个锁并不是可重入的。(在lock函数内,应验证线程是否为已经获得锁的线程)
2、若1问题已经解决,当unlock()第一次调用时,就已经将锁释放了。实际上不应释放锁。
(采用计数次进行统计)
修改之后,如下:
该自旋锁即为可重入锁。
自旋锁代码如下:
public class SpinLock { private AtomicReference<Thread> owner =new AtomicReference<>(); public void lock(){ Thread current = Thread.currentThread(); while(!owner.compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); owner.compareAndSet(current, null); }}
对于自旋锁来说:
1、若有同一线程两次调用lock() ,会导致第二次调用lock位置进行自旋(意思是第一次调用已经获得锁了,则第二次调用无法获得这个锁),产生了死锁
说明这个锁并不是可重入的。(在lock函数内,应验证线程是否为已经获得锁的线程)
2、若1问题已经解决,当unlock()第一次调用时,就已经将锁释放了。实际上不应释放锁。
(采用计数次进行统计)
修改之后,如下:
public class SpinLock1 { private AtomicReference<Thread> owner =new AtomicReference<>(); private int count =0; public void lock(){ Thread current = Thread.currentThread(); if(current==owner.get()) { count++; return ; } while(!owner.compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); if(current==owner.get()){ if(count!=0){ count--; }else{ owner.compareAndSet(current, null); } } }}
该自旋锁即为可重入锁。
链接:http://www.jianshu.com/p/007bd7029faf
0 0
- java 锁与可重入锁
- JAVA 线程与锁
- Java 同步与锁
- java线程与锁
- Java并发编程——锁与可重入锁
- 10018---Java并发编程——锁与可重入锁
- java的线程与锁
- Java显示锁与条件
- Java类加载与锁
- Java 多线程同步与锁
- java 线程 同步与锁
- Java线程同步与锁
- java & 与 &&
- java & 与&&
- java Java与编码
- [Java]Java与JavaScript
- Java锁与性能相关知识复习与整理
- java对象锁与类锁区别
- UVALive
- 工厂模式
- AsyncTask之加载图片
- python-框架-网页爬虫-文本处理-科学计算-可视化-机器学习-数据挖掘-深度学习
- 常用网站
- java 锁与可重入锁
- ELK框架搭建
- 【数据库系统概念部分习题】第二章 关系模型介绍
- pat 1073. Scientific Notation
- JWT(JSON Web Token)
- 常用软件
- win2012从远程主机copy文件
- 学习设计模式基础的心得与代码(一)
- 常用第三方开源包