2_Synchronized和Lock

Posted root_zhb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2_Synchronized和Lock相关的知识,希望对你有一定的参考价值。

1、多线程编程步骤

  1. 创建资源类,在资源类中创建属性和方法
  2. 在资源类操作方法
    • 判断
    • 干活
    • 通知
  3. 创建多个线程,调用资源类的操作方法
  4. 防止虚假唤醒问题

2、Synchronized

2.1、Synchronized作用范围

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4. 修饰一个类,其作用的范围是 synchronized 后面括号括起来的部分,作用的对象是这个类的所有对象。

2.2、Synchronized实现卖票例子

class Ticket {
    //票数
    private int number = 30;
    //操作方法:卖票
    public synchronized void sale() {
        //判断:是否有票
        if(number > 0) {
            System.out.println(Thread.currentThread().getName()+" : "+(number--)+" "+number);
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();

        new Thread(()->{
            for(int i=0;i<40;i++){
                ticket.sale();
            }
        },"AA").start();

        new Thread(()->{
            for(int i=0;i<40;i++){
                ticket.sale();
            }
        },"BB").start();

        new Thread(()->{
            for(int i=0;i<40;i++){
                ticket.sale();
            }
        },"CC").start();
    }
}

3、Lock

3.1、Lock简介

  1. Lock接口的所有实现类

    • 可重入锁(普通锁) :ReentrantLock
    • 读锁:ReentrantReadWriteLock.ReadLock
    • 写锁:ReentrantReadWriteLock.WriteLock
  2. Lock用法

    // 以可重入锁为例
    Lock lock = new ReentrantLock();
    // 加锁
    lock.lock();
    try{
        // 业务代码
    }catch(){
        
    }finally{
        // 解锁
        lock.unlock();
    }
    
  3. ReentrantLock构造方法

    //默认非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    
  4. 非公平锁和公平锁

    • 公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。(先来后到)
    • 非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。()

3.2、Lock卖票

class Ticket {
    //票数
    private int number = 30;

    //创建可重入锁
    private final ReentrantLock lock =new ReentrantLock();
    //操作方法:卖票
    public synchronized void sale() {
        //上锁
        lock.lock();
        try {
            //判断:是否有票
            if(number > 0) {
                System.out.println(Thread.currentThread().getName()+" : "+(number--)+" "+number);
            }
        }finally {
            lock.unlock();
        }
    }
}

4、Lock和Synchronized对比

  1. Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现;

  2. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;
    Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;

  3. Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用synchronized 时,等待的线程会一直等待下去,不能够响应中断

  4. 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。

  5. Lock 可以提高多个线程进行读操作的效率。

    在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时 Lock 的性能要远远优于synchronized。

以上是关于2_Synchronized和Lock的主要内容,如果未能解决你的问题,请参考以下文章

synchronized和lock的区别

Synchronized和lock的区别和用法

synchronized 和 lock 的区别

Java--多线程之synchronized和lock;死锁

synchronized关键字,Lock对象,阻塞队列问题

kotlin,为什么反编译java代码将同步锁定块转换为synchronized(var1){} +代码块?