显示锁Lock和ReentrantLock

显示锁Lock和ReentrantLock

Lock是一个接口提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。包路径是:java.util.concurrent.locks.Lock。核心方法是lock(),unlock(),tryLock(),实现类有ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock。

看一下Lock接口有如下方法:

public abstract interface Lock {

       public abstract void lock();

       public abstract void lockInterruptibly() throws InterruptedException;

       public abstract boolean tryLock();

       public abstract boolean tryLock(long paramLong , TimeUnit paramTimeUnit) throws InterruptedException;

       public abstract void unlock();

       public abstract Condition newCondition();

}

对应的解说如下:

void lock();获取锁。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。
void lockInterruptibly() throws InterruptedException;如果当前线程未被中断,则获取锁。如果锁可用,则获取锁,并立即返回。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:锁由当前线程获得;或者其他某个线程中断 当前线程,并且支持对锁获取的中断。如果当前线程:在进入此方法时已经设置了该线程的中断状态;或者在获取锁时被中断 ,并且支持对锁获取的中断,则将抛出  InterruptedException ,并清除当前线程的已中断状态。
boolean tryLock();仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值  true 。如果锁不可用,则此方法将立即返回值  false 。通常对于那些不是必须获取锁的操作可能有用。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。如果锁可用,则此方法将立即返回值  true 。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态:
void unlock();释放锁。对应于lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,如果成功的话应该对应着一个unlock(),这样可以避免死锁或者资源浪费。

newCondition() 返回用来与此 Lock 实例一起使用的 Condition 实例。

ReentrantLock是Lock的实现类,是一个互斥的同步器,它具有扩展的能力。在竞争条件下,ReentrantLock 的实现要比现在的 synchronized 实现更具有可伸缩性。(有可能在 JVM 的将来版本中改进 synchronized 的竞争性能)这意味着当许多线程都竞争相同锁定时,使用 ReentrantLock 的吞吐量通常要比 synchronized 好。换句话说,当许多线程试图访问 ReentrantLock 保护的共享资源时,JVM 将花费较少的时间来调度线程,而用更多个时间执行线程。虽然 ReentrantLock 类有许多优点,但是与同步相比,它有一个主要缺点 — 它可能忘记释放锁定。ReentrantLock实在工作中对方法块加锁使用频率最高的。

使用方法如下:

class X {

       private final ReentrantLock lock = new ReentrantLock();

       // …

       public void m() {

               lock.lock(); // 获得锁

               try {

                      // … 方法体

               } finally {

                     lock.unlock();//解锁

               }

       }

}
Lock与synchronized 的比较:

1:Lock使用起来比较灵活,但是必须有释放锁的动作;

2:Lock必须手动释放和开启锁,synchronized 不需要;

3:Lock只适用与代码块锁,而synchronized 对象之间的互斥关系;

请注意以下两种方式的区别:

第一种方式:两个方法之间的锁是独立的。如下:

public class ReentrantLockDemo {

       public static void main(String[] args) {

               final Count ct = new Count();

               for (int i = 0; i < 2; i++) {

                      new Thread() {

                              @Override

                              public void run() {

                                      ct.get();

                              }

                     }.start();

               }

 

             for (int i = 0; i < 2; i++) {

                    new Thread() {

                            @Override

                            public void run() {

                                    ct.put();

                            }

                    }.start();

              }

      }

}

class Count {

       public void get() {

              final ReentrantLock lock = new ReentrantLock();

              try {

                    lock.lock(); // 加锁

                    System. out.println(Thread.currentThread().getName() + “get begin”);

                    Thread. sleep(1000L);// 模仿干活

                    System. out.println(Thread.currentThread().getName() + “get end”);

                    lock.unlock(); // 解锁

              } catch (InterruptedException e) {

                    e.printStackTrace();

              }

       }

       public void put() {

              final ReentrantLock lock = new ReentrantLock();

              try {

                     lock.lock(); // 加锁

                    System. out.println(Thread.currentThread().getName() + “put begin”);

                    Thread. sleep(1000L);// 模仿干活

                    System. out.println(Thread.currentThread().getName() + “put end”);

                    lock.unlock(); // 解锁

             } catch (InterruptedException e) {

                   e.printStackTrace();

            }

      }

}

运行结果如下(每次运行结果都是不一样的,仔细体会一下):

Thread-0get begin

Thread-1get begin

Thread-2put begin

Thread-3put begin

Thread-0get end

Thread-2put end

Thread-3put end

Thread-1get end

第二种方式,两个方法之间使用相同的锁。

ReentrantLockDemo 类的内容不变,将Count中的ReentrantLock改成全局变量,如下所示:

class Count {

       final ReentrantLock lock = new ReentrantLock();

       public void get() {

              try {

                     lock.lock(); // 加锁

                     System. out.println(Thread.currentThread().getName() + “get begin”);

                     Thread. sleep(1000L);// 模仿干活

                     System. out.println(Thread.currentThread().getName() + “get end”);

                     lock.unlock(); // 解锁

               } catch (InterruptedException e) {

                    e.printStackTrace();

               }

}

       public void put() {

              try {

                    lock.lock(); // 加锁

                    System. out.println(Thread.currentThread().getName() + “put begin”);

                    Thread. sleep(1000L);// 模仿干活

                    System. out.println(Thread.currentThread().getName() + “put end”);

                    lock.unlock(); // 解锁

              } catch (InterruptedException e) {

                    e.printStackTrace();

             }

      }

}

运行结果如下(每次运行结果一样的,仔细体会一下):

Thread-0get begin

Thread-0get end

Thread-1get begin

Thread-1get end

Thread-2put begin

Thread-2put end

Thread-3put begin

Thread-3put end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值