【心得】高频面试题:如何使用synchronized锁?三种使用方式详细解析与实际代码展示!


前言

synchronized 是 Java 中最简单且最常用的线程同步机制,适用于大多数简单的线程安全场景。它通过内置锁机制确保代码的互斥性和内存可见性,且在现代 Java 版本中性能表现良好。掌握synchronized锁的使用十分有必要。本文会聊聊对synchronized锁的三种使用方法,并给出实际代码进行展示。


一、如何使用synchronized锁?

答:synchronized关键字有三种使用方式:
1、 修饰实例方法(锁实例对象)
2、 修饰静态方法 (锁当前类)
3、 修饰代码块 (锁指定对象/类)
先把这几句话给记牢,然后再结合具体例子来理解

一句话解释概念:实例方法是指属于对象的方法,而静态方法属于类。代码块则是用大括号包围的一段代码。

二、修饰实例方法(锁实例对象)

代码如下(示例):

public class Counter{
    private int count = 0;
    //synchronized 修饰实例方法
    public synchronized void increment(){
         count++;
    }
    public int getCount(){
       return count;
    }
}

实例方法:increment() 方法属于 Counter 类的实例对象(需通过 new Counter() 创建对象后调用),它就是一个实例对象。
锁对象‌:锁的是调用该方法的实例对象(即 this)。(ps: this 在实例方法中的本质:指向当前实例的引用)
o 若线程 A 和线程 B 调用‌同一个‌ Counter 实例的 increment() 方法,会互斥执行‌。
o 若两个线程分别调用‌不同‌ Counter 实例的 increment() 方法,不会互斥(因为锁的是各自实例)‌。

三、修饰静态方法(锁当前类)

public class Counter{
    private static int count = 0;
    //synchronized 修饰实例方法
    public static synchronized void increment(){
         count++;
    }
    public int getCount(){
       return count;
    }
}

这里的increment属于静态方法,静态方法与实例方法的区别有:
实例方法:
与对象实例相关联,依赖于对象调用。
可以访问实例变量和实例方法。
可以被重写(Overriding)。
适用于操作对象状态的场景。
静态方法:
与类相关联,不依赖于对象实例。
只能访问静态变量和静态方法。
不能被重写(Overriding),但可以被重载(Overloading)。
适用于工具类、工厂方法等不依赖于对象状态的场景

静态方法 increment() 方法属于 Counter 类本身(可通过 Counter.increment() 直接调用)

锁对象‌:锁的是类的 Class 对象(即 Counter.class)。
无论有多少个 Counter 实例,所有线程调用 increment() 方法都会互斥‌。
所以若一个线程调用实例的 synchronized 方法(非静态),另一个线程调用静态的 synchronized 方法,不会互斥(因为锁对象不同:前者是实例,后者是类)‌

三、修饰代码块

public class Counter{
    private int count = 0;
    private final Object lock = new Object();
 
    //synchronized 修饰代码块
    
    public void increment(){
     //synchronized 修饰代码块 锁指定对象
         synchronized(lock){
             count++;
         }
    }
    public static void staticIncrement(){
     //synchronized 修饰代码块,锁类对象
     synchronized(Counter.Class){
        // 操作静态变量
     }    
    } 
}

代码块‌:通过 synchronized(锁对象) 包裹需要同步的代码片段。
锁对象‌又分为两种:
实例对象锁 ‌synchronized(object):例如 synchronized (lock),锁的是 lock 对象。多个线程访问同一 lock 对象的代码块时会互斥‌。
类对象锁‌ synchronized(类.class):例如 synchronized (Counter.class),锁的是类的 Class 对象。此时与修饰静态方法等效,所有实例的线程都会互斥‌。


总结

其实我觉得客观来讲,synchronized的使用方式只有两种,一种是修饰方法,一种是修饰代码块。修饰方法又分为修饰实例方法与静态方法,修饰实例方法锁的就是实例对象,修饰静态方法锁的就是当前类,而修饰代码块的话,则锁的是由synchronized(锁对象)里面的这个锁对象,可能为实例对象,也可能为类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值