「这是我参与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实现)