java中Lock的用法以及Lock与synchronized的区别

Java中除了synchronized外,jdk还提供了Lock来实现共享互斥,Lock实现提供比synchronized方法和语句更广泛更灵活的锁定操作,而且还可以支持多个相关联的对象,本文就来介绍一下Lock。

首先还是通过源码大致了解一下Lock是个什么东西:

public interface Lock{
    void lock();
    void lockInterruptibly();
    boolean tryLock();
    boolean tryLock(long arg0 , TimeUnit arg1) throws InterruptedException;
    void unlock();
    Condition newCondition();
}
根据注释挨个了解一下这些方法:

1、lock()

尝试去获取锁,如果锁暂时被其他线程持有,则会处于休眠状态,直到当前线程获得锁。

因为需要在执行完临界区之后释放锁,所以典型用法是这样的:

Lock lock = ...;
try{
    // 执行临界区
}
finally{
    lock.unlock();//放在finally块,确保锁的释放
}

2、lockInterruptibly

尝试去获取锁,如果锁暂时被其他线程持有,则会处于休眠状态,直到当前线程获得锁或者被其他线程interrupt()。


3、tryLock()

尝试获取锁,立刻拿到锁返回true,没拿到立刻返回false,也就是这样的获取锁的方式不等待。

典型用法如下:

Lock lock = ...;
if(lock.tryLock()){
    try{
         //执行临界区
    }
    finally{
        lock.unlock();
    }
}
else{
    //执行没有获取锁的其他操作
}

4、tryLock(long time, TimeUnit unit) throws InterruptedException

尝试获取锁,如果锁可用,立刻拿到锁返回true,否则进入休眠状态,直到当前线程拿到锁或者被其他线程interrupt()或者过去了指定时间长度。

当锁获取到则返回true,否则返回false。


5、unlock()

释放锁。


6、newCondition()

返回一个新的condition绑定到该实例Lock示例。


已知有ReentrantLock,ReentrantLockReadWriteLock.ReadLock,ReentrantLockReadWriteLock.WriteLock实现了这个接口。


先看一下ReentrantLock

ReentrantLock和synchronized都是可重入锁,所谓可重入锁就是在一个线程中可以多次获得同一把锁,比如一个线程执行一个带锁的方法,该方法中又调用了另一个需要同样锁的方法,那么该线程可以直接执行调用的方法,而无需重新获得锁。

这种可重入的特性好处就在于避免了死锁的发生,举个知乎上的例子:

public class Parent{
    public synchronized void doSomething(){
        //to do
    }
}

public class Sub extends Parent{
    public synchronized doSomething(){
        super.doSomething();
    }
}
这种情况下如果不是可重入的就会产生死锁,首先理解理解这段代码需要搞懂一个问题。

Sub对象执行doSomething()时候所获取的锁和在这个方法内执行super.doSomething()所需要获取的锁一样吗?

因为执行这两个synchronized方法时的对象都是Sub对象,所以可以看成synchronized(this){//代码段} 因此是一样的。

如果不是可重入的时候,当前线程获得了Sub对象对应的锁,然后由于需要执行super.doSomething(),因此还需要当前的锁。相当于当前线程手握着Sub对象锁去执行一个需要Sub对象锁的方法,如果不是可重入的,就产生了死锁。

然而可重入的特点就使得这样的死锁情况不会发生,执行super.doSomething()的时候不需要重新获取锁,直接执行就可以。

ReentranLock和synchronized很相似,都具有一样的重入特性,但是前者是API层面的互斥锁,后者是原生语法层面的互斥锁。相对于synchronized,ReentranLock增加了一些高级功能:等待可中断可实现公平锁锁可以绑定多个条件

1、等待可中断指的是当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情(tryLock(long time, TimeUnit unit) throws InterruptedException)。

2、公平锁指的是当多个线程在等待同一个锁的时候,必须按照申请锁的时间顺序来依次获得锁,但是非公平锁不一样,锁释放的时候,任何一个等待的线程都有机会获得锁。synchronized中锁是非公平的,ReentrantLock默认情况下是非公平的,但是可以通过带布尔值的构造函数构造公平锁。

3、锁绑定多个条件是指一个ReentrantLock对象可以同时绑定多个Condition对象。

而至于ReentrantReadWriteLock就相当于我们之前说过的Read-Write lock pattern

jdk1.5及其之前synchronized是悲观锁,lock是乐观锁。并发不严重的时候synchronized比lock好,但是当并发特别严重的时候synchronized性能下降得很快,然而lock能基本保持稳定,这个时候就应该使用lock。

而jdk1.6及其以后synchronized和Lock都是CAS乐观锁,synchronized简单易用,而Lock则能控制并发更精巧,具体选择哪个就看需要了。

CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值