笔记 5 · interface Lock锁

Lock 简介

Lock锁相对于synchronized关键字,它更加灵活(允许在不同的作用域中获取和释放锁,并允许以任何顺序获取和释放多个锁),并支持多个关联的Condition对象。
有些锁允许并发访问共享资源,例如读写锁的读锁。
随着灵活性的提高,我们需要承担更多的责任。Lock务必要通过unlock() 方法在finally块中执行,以确保在必要时释放锁。

Lock 与synchronized在锁的处理上的重要差别

  • 锁的获取方式:
    Lock是通过程序代码的方式由开发者 手工获取lock()、tryLock()…
    Synchronized是通过JVM获取(无需开发者干预)。
  • 具体实现方式:
    Lock是通过程序代码的方式实现。
    Synchronized是通过JVM获取(无需开发者干预)。
  • 锁的释放方式:
    Lock务必要通过unlock() 方法在finally块中手工释放。
    synchronized是通过JVM释放(无需开发者干预)。

    synchronized获取多个锁后(lock_1, lock_2),释放要以相反的顺序释放( lock_2, lock_1)。
    Lock锁的释放,没有这种要求。
  • 锁的具体类型:
    Lock提供了公平锁、非公平锁。
    Synchronized与 Lock均提供了 可重入锁。

结构图

在这里插入图片描述

方法

void lock();

  • 获取锁。如果锁不可用,则当前线程将处于休眠状态,直到获得锁为止。

void lockInterruptibly() throws InterruptedException;

  • 除非当前线程中断,否则获取锁。
  • 如果可用,则获取锁并立即返回。
  • 如果锁不可用,则当前线程将处于休眠状态,直到发生以下两种情况之一:
  • 1、当前线程获取锁。
  • 2、其他线程中断当前线程,支持中断锁采集。

boolean tryLock();

  • 尝试非阻塞的获取锁。仅当在调用时锁是空闲的才获取锁。
  • 获取锁(如果可用),并立即返回值true。如果锁不可用,则此方法将立即返回值false。
  • 此方法的典型用法是:
  •      Lock lock = ...;
         if (lock.tryLock()) {
            try {
               // 操纵受保护状态
            } finally {
               lock.unlock();
            }
          } else {
             // 执行替代操作
          }
    

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

  • 如果锁在给定的等待时间内空闲且当前线程没有中断,则获取该锁。
  • 如果时间小于或等于零,则该方法根本不会等待。
  • 如果锁可用,此方法立即返回值true。如果锁不可用,则出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到发生以下三种情况之一:
  • 1、当前线程在超时时间内获得锁
  • 2.、当前线程在超时时间内被中断
  • 3、 超时时间结束,返回false
  • 如果当前线程,在获取锁时被中断,会抛出异常并清除当前线程的中断状态。

voidunlock();

  • 释放锁

Condition newCondition();

  • 返回绑定到此锁实例上的一个新Condition实例。

在这里插入图片描述

案例:演示可重入性

class MyLock {
    // 可重入锁, 表示同一个线程可以重复获取到刚获取过的锁。
    private Lock lock = new ReentrantLock();

    public void myThread1() {
   		lock.lock();
        try {
            // 这个方法会被执行10次,因为lock是可重入锁,在线程t2拿不到锁的情况下,
            // 线程t1虽然没有释放锁,但却可以重复执行。
            System.out.println("myThread1");
        } finally {
            // lock.unlock();
        }
    }

    public void myThread2() {
   		 // 这个方法不会被执行,因为 线程t1,未释放锁。
        //线程t2会一直等待,直到获取到锁。
        lock.lock();
        try {
            System.out.println("myThread2");
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        MyLock myTest = new MyLock();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                myTest.myThread1();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                myTest.myThread2();
            }
        });
        // 程序因为线程t1没有释放锁,所以在执行完10次myMonth1方法后,程序会继续等待,
        //不能正常退出。
        t1.start();
        t2.start();
    }
    // 线程1结束
    // 线程2 被挂起等待。
    // 但可以看出,线程1在没有释放锁的情况下,同一个线程可以多次访问。
}

程序修正:

public void myThread2() {
    boolean result = false;
     try {
         result = lock.tryLock(800, TimeUnit.MICROSECONDS);
     } catch (Exception e){
     }
     if (result) {
         System.out.println("get the lock");
     } else {
         System.out.println("can't get the lock");
     }
 }
 // 如果把myMonth2方法改成这样,虽然线程t2还是获取不到锁,
 // 但却可以在执行完10次myMonth1方法后,正常退出。

输出信息:
myThread1 * 10 遍
can’t get the lock * 10 遍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值