synchronized和lock的区别

一、共同点

当出现互斥资源时,期望一段代码同时只能一个线程访问,如商品抢购活动,多线程同时操作数据库可能导致数据错误。

二、区别

  1. synchronized 是JVM内置的关键字,Lock是java.util.concurrent.Locks 包下的一个接口。

  2. synchronized 不管是否出现异常,会自动释放锁;Lock需要手动释放锁,尤其是在出现异常时,一定要在finally中手动释放,否则将出现死锁。

  3. synchronized 不可中断,Lock可以中断。

  4. synchronized 无法自动获得锁是否成功。

    2.1 synchronized 使用

    一个类有一个类锁,一个对象有一个对象锁。

    synchronized 可修饰以下几种情况。

    • 修饰代码块,被修饰的代码块使用{}包含,获得对象锁。
    • 修饰方法,作为范围为整个方法,获得对象锁
    • 修饰静态方法,获得类锁。
    • 修饰类,获得类锁。

    1、修饰代码块

    ​ 一个线程访问一个对象中的synchronized(this)同步代码块时,第一个线程获得锁成功访问,其他线程被阻塞,等待获得锁的线程执行完后自动释放锁。(多个线程必须是同一对象访问同步代码块)

 @PostMapping("/testsynchronized")
 public ApiResult testsynchronized() throws InterruptedException {
     synchronized (this){
     System.out.println(Thread.currentThread().getName()+"进入同步代码块");
     Thread.sleep(5000);
     System.out.println(Thread.currentThread().getName()+"同步代码块结束");
     }
 }

2、修饰方法

​ 作用跟修饰代码块相同,作用范围为整个方法

 @PostMapping("/testsynchronized")
 public ApiResult testsynchronized() throws InterruptedException {
     testsynchronizedMothd();
 }
 
 private synchronized void testsynchronizedMothd() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"进入同步方法");
        Thread.sleep(5000);
        System.out.println(Thread.currentThread().getName()+"同步方法结束");
    }

3、修饰静态方法

由于静态方法属于类所有,和修饰方法的区别在于同一个类的所有对象访问该方法都将互斥,竞争类锁。

4、修饰类

在方法中使用synchronized(类名.class) 同样活动类锁。

class ClassName {
   public void method() {
      synchronized(ClassName.class) {
         
      }
   }
}

2.2 .Lock的用法

Lock是一个接口,有很多实现类,常用的有ReentrantLock

Lock一些常用的方法。

  1. lock();获得锁,成功则执行同步代码,不成功则阻塞。

    private Lock lock = new ReentrantLock();
    @PostMapping("/testsynchronized")
    public ApiResult testsynchronized() throws InterruptedException {
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"上锁成功");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println(Thread.currentThread().getName()+"释放锁");
            lock.unlock();
        }
    }
    
  2. tryLock();有返回值,获得锁成功返回true,否则返回false。

    private Lock lock = new ReentrantLock();
    @PostMapping("/testsynchronized")
    public ApiResult testsynchronized() throws InterruptedException {
            if(lock.tryLock()){
                System.out.println(Thread.currentThread().getName()+"上锁成功");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println(Thread.currentThread().getName()+"释放锁");
                    lock.unlock();
                }
            }else{
                System.out.println(Thread.currentThread().getName()+"获取锁失败");
            }
    }
    
  3. tryLock(long time, TimeUnit unit);有返回值,活动锁成功则返回true,不成功不会马上返回,会在传入的时间内不断的尝试获得锁,期间获得锁成功返回true,如果时间结束都还没活动所则返回false。

    private Lock lock = new ReentrantLock();
    @PostMapping("/testsynchronized")
    public ApiResult testsynchronized() throws InterruptedException {
         boolean tryLock = lock.tryLock(5,TimeUnit.SECONDS);
            if(tryLock){
                System.out.println(Thread.currentThread().getName()+"上锁成功");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    System.out.println(Thread.currentThread().getName()+"释放锁");
                    lock.unlock();
                }
            }else{
                System.out.println(Thread.currentThread().getName()+"获取锁失败");
            }
    }
    
  4. lockInterruptibly(),同样会阻塞,区别在于如果线程在等待,这个线程可以响应中断,即中断线程的等待状态。

posted @ 2022-01-25 14:58  pu_xb  阅读(215)  评论(0编辑  收藏  举报