java 加锁_Java中加锁的方法

Java中的锁。Synchronized和Lock。

开始

今天,我们来聊聊java中的锁。

471f89b5772d67107a7abdb87bccda63.png

锁的三个问题

锁是一种互斥的机制,在多线程环境中实现对资源的强制控制,以帮助实现并发控制。

锁的使用会带来三个问题:1. 锁开销。锁会占用内存空间。锁的初始化,销毁,获取和释放,都需要消耗CPU时间。

2. 锁竞争。一个线程试图在另一个线程已经获取锁的资源上获取锁时,就会发生锁竞争。

3. 死锁。至少有两个线程,都在等待获取对方所持有的锁时,就会发生死锁。死锁有一个著名的案例,即哲学家就餐问题。说有五个哲学家,围坐就餐,每两个人的中间放一只筷子,即有五支筷子。得到开饭指令后,每人都先去拿右边的筷子,再去拿左边的筷子,拿到一双筷子就可以开始吃饭。分析这个案例,我们发现,如果五个人都处于一个竞争的状态的话,那么,每个人都会处在一个等待左边的人吃完的状态。于是,就发生了死锁。

基于以上三个问题,就要求在使用锁的时候,需要一定的策略性。如优化锁的获取和释放机制,更细粒度的去加锁等。

Synchronized

synchronized关键字可以帮助我们给一个类对象或者实例对象加锁。常见用法如加在某个方法上,加在代码块上。当加在方法上时,如果该方法是静态方法,则锁住的是类对象,如加在非静态方法上,则锁住的是实例对象。当加在代码块上时,要看给的参数是什么,如果是***.class,则锁住的是类对象,如果是this或某个实例,则锁住的是当前实例对象或指定的实例对象。

这里,有个问题是锁住的目标和被锁定的代码块之间,存在什么样的关系?必须深刻理解这个问题,才算是真正明白了synchronized关键字。

想象有若干个房间,每个房间都上了锁,当要进入某个房间时,就必须先拿到这个房间的钥匙,必然,前提就是钥匙没有被别人拿走。线程也是如此,被锁定的方法或代码块就好比房间,锁住的目标就相当于钥匙。接下来,我们引入同步和异步的概念,帮助我们做接下来的分析。

线程同步指的是,若干线程不可以同时执行,当某一个线程处于运行状态时,其他线程一定处于就绪或阻塞状态。

线程异步指的是,若干线程是可以同时执行的,他们之间不存在相互影响,当一个线程处于运行状态时,其他线程也可以运行。

联系到锁的话,我们得到,若干线程同步的条件之一是,他们要执行的方法或代码块,使用了同样的锁定对象。假设有类A,有a、b两个线程使用了synchronized关键字,c是A类的一个静态类变量。

d9792dad1623a041c6efcb1ebdcc0cf6.png

事实上,实际情况比上表要复杂,但是判断的核心依据是相同的:是不是同一把锁(同一把钥匙)。

Lock

Lock是另一种帮助加锁的机制。使用Lock时,你需要一个Lock对象,例如lock。你需要通过调用 lock的lock、unlock等方法,为某段代码加锁。使用lock时,判断多个线程是同步或异步,核心判断依据是所使用的lock是不是同一个对象,是即为同步,不是即为异步。

例如,A类包含一个Lock类型的类变量lock,可能通过构造方法或者lock的set方法等,传入一个Lock实例到lock变量。A类中,代码块a、b都使用了lock的相关方法加锁。现在有线程t1和t2,那么,他们在调用a或b时,是同步还是异步呢?

我们说,主要取决于在给类变量lock赋值时,给的是不是同一个实例。如果都给lock1,就是同步,一个给lock1,另一个给lock2,就是异步。

可重入锁

一个线程,可以对自己已经获取锁的对象再次加锁(线程内部,如递归),称之为可重入锁。可重入锁的实现机制一般是给锁加一个计数标识。线程每获取锁一次,该计数标识加1,每释放锁一次,该计数标识减1。当减至0时,说明该线程完全释放了目标对象的锁。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值