并发编程笔记七:显示锁

七、显示锁

7.1、内置锁synchronized的缺陷

       内置锁使用的格式

       synchronized(锁对象){ // 获取锁,获取不到会一直阻塞
              同步代码块
       }      // 释放锁

 

缺陷:

获取锁的线程在无法获取锁的时候,会一直阻塞在获取锁的位置,无法中止,会无限的等待下去。无法对获取不到锁做相关的逻辑操作,也无法设置获取锁的超时时间,也无法强制中断获取锁的操作。

当发生死锁时,只能重启应用解决。

7.2、显示锁Lock

显示锁可以解决上述内置锁的缺陷。

Lock是一个接口,最常用的实现类就是ReentrantLock。

Lock接口代码如下:

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

 

(1)void lock()

获取锁,与内置锁synchronized一样,会一直阻塞在这里,无法中止。

使用方式:

              Lock lock =new ReentrantLock();
              lock.lock();
              try{
                     需要同步的代码
              }finally{
                     lock.unlock();
              }

 

(2)void lockInterruptibly() throws InterruptedException

获取锁,当收到中断信号后,该方法会抛出InterruptedException中断异常。阻塞中止。

该方法可以被其他线程中断。

使用方法

              Lock lock =new ReentrantLock();
              try{
                     lock.lockInterruptibly();
                     try{
                            需要同步的代码
                     }finally{
                            lock.unlock();
                     }
              }catch(InterruptedException e){
                     // 获取锁时被中断的处理代码
              }

 

(3)boolean tryLock();

获取锁不会阻塞并立即返回,获取成功返回true,获取失败返回false。

因为可以知道获取锁是否成功,可以执行相关的不同逻辑操作,所以更加灵活了。

使用方法:

              Lock lock = new ReentrantLock();
              while(true){
                     boolean isLock = lock.tryLock();
                     if(isLock){
                            try{
                                   需要同步的代码
                                   break;
                            }finally{
                                   lock.unlock();
                            }
                     }else{ // else可省略
                            获取不到锁的处理代码,比如sleep一会再去获取
                     }
              }

 

(4)boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

获取锁,会阻塞指定时间段,如果在指定时间内获取到锁,会返回true,否则获取失败返回false。同时这个方法是可以被其他线程中断的。

使用方法:

              Lock lock = new ReentrantLock();
              try{
                     boolean isLock = lock.tryLock(1000L, TimeUnit.MILLISECONDS);
                     if(isLock){
                            try{
                                   需要同步的代码
                            }finally{
                                   lock.unlock();
                            }
                     }else{
                            超时获取不到锁的代码
                     }
              }catch(InterruptedException e){
                     被中断的处理代码
              }

 

(5)void unlock();

释放锁,为了保证锁的顺利释放,一般释放锁的代码放在finally块中执行。

(6)Condition newCondition();

获取当前锁的一个等待队列,可以利用wait/notify机制进行通信。

详见笔记九,9.6小节。

7.3、ReentrantLock可重入锁

ReentrantLock内部维护了两个互斥锁,分别是FairSync公平锁和NonfairSync非公平锁,通过ReentrantLock的有参构造public ReentrantLock(boolean fair)决定使用的是哪种锁,默认无参构造使用的是非公平锁。

public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

 

ReentrantLock类图如下:

非公平锁理论上性能比公平锁好,所以最好使用非公平锁。

7.4、读写锁ReadWriteLock

读写锁的接口是ReadWriteLock,实现类是ReentantReadWriteLock

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}

 

通过readLock()方法获取读锁,读锁就是个Lock;

通过WriteLock()方法获取写锁,写锁也是一个Lock。

读写锁的读锁和读锁是共享的,读锁和写锁是独占的,写锁和写锁时独占的。类似于mysql中的S锁和X锁。

http://ifeve.com/read-write-locks/#simple

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值