2025-06-30 20:30:21Java锁到底是个什么东西

一、java锁存在的必要性

要认识java锁,就必须对2个前置概念有一个深刻的理解:多线程和共享资源。

对于程序来说,数据就是资源。

在单个线程操作数据时,或快或慢不存在什么问题,一个人你爱干什么干什么。

多个线程操作各自操作不同的数据,各干各的,也不存在什么问题。

多个线程对共享数据进行读取操作,我就四处看看,什么也不动,也不存在什么问题。

但如果多个线程对共享数据进行写操作,问题就来了。

经典库存问题:

mysql 记录剩余:1,redis 缓存记录剩余:1。

小明上网下单,后台程序检查 redis 记录存货剩 1 台,数据库执行 -1,但小明网太卡了,数据库刚执行完 -1,redis 没来得及更新成0,小红的华为5G直接下单,redis 剩1台,数据库-1,redis -1,下单成功一气呵成。结果就是2个人买了同一台手机。

这种业务场景可以说比比皆是,所以要解决这种数据同步问题就要有对应的办法,所以发明了java锁这个工具来保证数据的一致性,举个例子:

在一个不分男女的公共厕所中上一把锁,有人进去,把门锁住,上完出来,把锁打开,以此类推。

二、2个重要的java锁

synchronized关键字

synchronized关键字是java开发人员最常用的给共享资源上锁的方式,也基本可以满足一般的进程同步要求,使用 synchronized 无需手动执行加锁和释放锁的操作,只需在需要同步的代码块、普通方法、静态方法上加入该关键字即可,JVM 层面会帮我们自动的进行加锁和释放锁的操作。

修饰普通方法

/**

* synchronized 修饰普通方法

*/

public synchronized void method() {

// ....

}

当 synchronized 修饰普通方法时,被修饰的方法被称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象。

修饰静态方法

/**

* synchronized 修饰静态方法

*/

public static synchronized void staticMethod() {

// .......

}

当 synchronized 修饰静态方法时,其作用范围是整个程序,这个锁对于所有调用这个锁的对象都是互斥的。

修饰普通方法 VS 修饰静态方法

创建一个类,其中有synchronized修饰的普通方法和synchronized修饰的静态方法。

public class SynchronizedUsage {

/**

* synchronized 修饰普通方法

*/

public synchronized void method() {

System.out.println("普通方法执行时间:" + LocalDateTime.now());

try {

// 休眠 3s

TimeUnit.SECONDS.sleep(3);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/**

* synchronized 修饰静态方法

*/

public static synchronized void staticMethod() {

System.out.println("静态方法执行时间:" + LocalDateTime.now());

try {

// 休眠 3s

TimeUnit.SECONDS.sleep(3);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

测试

public class Test01 {

/**

* 创建线程池同时执行任务

*/

static ExecutorService threadPool = Executors.newFixedThreadPool(10);

public static void main(String[] args) {

// 执行两次静态方法

threa