多线程(二)--锁的基础知识(一)

144 阅读3分钟

「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

多线程(一)--基础概念补充 这篇主要一起研究锁的概念

一、类锁和对象锁

synchronized有类锁和对象锁

  • 对象锁:synchronized 修饰非静态的方法和synchronized(this)都是使用的对象锁,多个线程访问同一个对象实例的这个方法时,是会同步的,并且只有一个线程执行完,另一个线程才会执行
public class MainDemo {
    public synchronized void method3(){
        System.out.println("------我是对象锁1------");
    }

    public void method4(){
        synchronized (this){
            System.out.println("------我是对象锁2------");
        }
    }
}
  • 类锁:锁是加持在类上的,用synchronized static 或者synchronized(class)方法使用的锁都是类锁,因为class和静态方法在系统中只会产生一份,所以在单系统环境中使用类锁是线程安全的
public class MainDemo {
    public synchronized static void method1(){
        System.out.println("------我是类锁1------");
    }
    public void method2(){
        synchronized (MainDemo.class){
            System.out.println("------我是类锁2------");
        }
    }

二、Lock

Lock代表实现类是ReentrantLock(可重入锁)

  • void lock():获取锁,如果锁不可用,则出于线程调度的目的,当前线程将被禁用,并且在获取锁之前处于休眠状态
  • void lock():boolean tryLock():如果锁可用立即返回true,如果锁不可用立即返回false
  • void lock():boolean tryLock(long time, TimeUnit unit) throws InterruptedException:如果锁可用,则此方法立即返回true。 如果该锁不可用,则当前线程将出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一为止:(1)当前线程获取到该锁;(2)当前线程被其他线程中断,并且支持中断获取锁;(3)经过指定的等待时间如果获得了锁,则返回true,没获取到锁返回false
  • void unlock():释放锁。释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生

ReentrantLock锁

ReentrantLock是乐观锁类型,多线程并发情况下。能保证共享数据安全性,线程间有序性 ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁

二、synchronized和Lock的对比

  • synchronized是Java内置的关键字,使用后会自动释放锁
  • Lock是java.util.concurrent.Locks 包下的一个接口,必须要手动释放。特别是在发生异常时,需要在 finally 块中进行手动释放,否则会发生死锁行为
  • Lock可响应中断,而synchronized 不能响应中断,并且Lock提供了更丰富的方法实现
  • synchronized 是非公平锁,即不能保证等待锁线程的顺序
  • Lock的实现 ReentrantLock 可通过实例化true or false 的构造参数实现公平锁和非公平锁,默认为非公平锁
  • synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
  • Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
  • 都是可重入锁:在执行对象中所有同步方法不用再次获得锁
  • synchronized是一个悲观锁,Lock是一个乐观锁(底层基于volatile和cas实现)