概述
锁
锁应用于java多线程中的同步机制,我们知道线程安全的问题大部分是由于多个线程并发的访问共享变量或共享数据。于是我们想到将并发访问变为串行访问,既一次只能有一个线程访问共享数据。这就是锁的思想
如果你学过操作系统的多线程同步机制的话,相信你会对这部分有更好的理解。在操作系统中,多线程的同步是通过p,v原语,既waite(),signal()来解决线程同步问题,在访问临界区之前,所谓临界区就是p,v原语中间的代码,我们首先要对线程进行资源的申请操作p,访问结束后我们使用v归还资源。
java多线程中的锁的概念和操作系统的锁的概念大同小异。对一个线程进行加锁,就是进行P操作向处理机请求分配资源并告诉其他线程当前线程正在使用临界区,你们没有锁这个钥匙不可访问。当这个线程访问结束后系统由JVM自动进行释放当前线程的锁的操作(相当于V)。锁具有排他性,一个锁一次只能被一个线程持有,因此这种锁被称为排他锁或互斥锁。
锁的分类
按照java虚拟机对锁的实现方式的划分,我们将锁分为内部锁和显示锁。其中,内部锁是通过synchronized 关键字来实现的。显示锁则是通过java.comcurrent.locks.Lock接口的实现类实现的。
内部锁synchroniezd关键字
java中任何一个对象都有一个内部锁。内部锁是一种排他锁。
内部锁是通过synchonized关键字来实现的,synchronized关键字可以修饰方法或代码块,被修饰的方法或代码块被称为同步方法或同步代码块,同步方法的方法体就是一个临界区。在对共享数据的访问时,线程必须向处理器申请该同步代码块的锁,当线程执行完毕后在对其进行释放。整个过程中,锁的申请和释放都是有java虚拟机代为实施,所以这是synchronized被称为内部锁的原因。
内部锁的调度
回想我们在操作系统中学过的同步机制,当一个临界区正在被一个线程占用的时候,其他线程是无法申请资源也无法进入这个临界区的,那么这些线程去哪儿了呢?当前一线程申请的临界区资源被释放又是怎么调度其他曾经申请该临界区的线程的?我们知道,当线程访问的临界区正在被占用时,处理器会将当前想访问却无法访问临界区的线程阻塞,并放入一个阻塞队列的最末尾,如果有多个线程想访问当前临界区也是由阻塞队列代为保管线程。等到占用线程被释放时,处理器会调用阻塞队列中的一个线程变为就绪状态申请资源进入临界区。
内部锁的调入也是这样。不同的是,我们将内部锁的阻塞队列称之为入口集,用于记录等待获得相应内部锁的线程。在java中对入口集中锁的调动支持的是非公平调用,具体如何调用应当参照当前java虚拟机所实现的调用算法。
显示锁 Lock接口
显示锁是java.util.concurrent.locks.Lock的接口实例,该接口对显示锁进行了抽象。方法如图所示
void | lock()获取锁 |
---|---|
void | lockInterruptibly 如果当前线程为被中断,则获取锁 |
Condition | newCondition() 返回绑定到此Lock实例的新condition实例 |
boolean | tryLock() 仅在调用时锁为空闲状态才获取该锁 |
void | unLock() 释放锁 |
private final Lock lock = ... ;//创建一个Lock接口实例
......
lock.lock() ; //申请该锁
try{
//共享区域
....
}finally{
//总是在finally中释放锁,避免**锁泄漏
lock.unlock(); //释放Lock
}
这里简单解释一下锁泄漏
所谓锁泄漏指的是一个线程获取某个锁之后,由于程序的错误,导致该锁一直无法进行释放而导致其他线程无法获取该锁的现象。锁泄漏可能导致死锁,锁死等故障。
显示锁与内部锁的比较
内部锁是基于代码块或方法体的锁,显示锁是基于对象的锁。显示锁可以充分发挥面向对象编程的灵活性。内部锁的申请与释放只能在一个方法内执行,而显示锁支持在一个方法中申请所,另一个方法中释放锁。内部锁中不存在锁泄漏问题,显示锁中要警惕锁泄漏。
最后
以上就是曾经电源为你收集整理的java多线程之锁的应用的全部内容,希望文章能够帮你解决java多线程之锁的应用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复