JAVA锁机制:对象锁与类锁

JAVA锁机制:对象锁与类锁

在多线程编程中,合理使用锁机制是保证数据一致性和线程安全的关键。本文将通过示例详细讲解 Java 中的对象锁和类锁的原理、用法及区别。

一、未加锁的并发问题

先看一段未加锁的代码:

java 复制代码
public class SynchronizedTest {
    private int shareField = 0;

    public void add() {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
    public static void main(String[] args) {
        SynchronizedTest sync = new SynchronizedTest();
        new Thread(() -> {
            for (int n = 0; n < 100000; n++) {
                sync.add();
            }
        }).start();
        new Thread(() -> {
            for (int n = 0; n < 100000; n++) {
                sync.add();
            }
        }).start();
    }
}

上述代码启动两个线程,每个线程各自循环10万次,对 shareField 进行自增。理论上,最终 shareField 应为 200000,但实际运行结果往往小于 200000:

复制代码
当前线程:Thread-0 当前的shareField为:199994
当前线程:Thread-0 当前的shareField为:199995
...

原因在于多个线程并发修改同一变量,导致数据竞争。


二、对象锁

对象锁用于保护同一个实例的资源,确保同一时刻只有一个线程能访问被锁定的代码块。

1. 锁定非静态方法

java 复制代码
public class SynchronizedTest {
    private int shareField = 0;

    public synchronized void add() {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
    // 省略 main 方法
}

synchronized 修饰非静态方法时,锁的是当前实例对象 (this)。

2. 锁定 this 对象(代码块)

有时只需对方法中的部分代码加锁,可以使用同步代码块:

java 复制代码
public void add() {
    synchronized (this) {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
}

3. 锁定特定对象

也可以指定其他对象作为锁:

java 复制代码
private final Object obj = new Object();
public void add() {
    synchronized (obj) {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
}
对象锁特点
  • 锁对象:当前实例(this)或指定对象
  • 多线程访问同一实例的同步方法时互斥
  • 不同实例之间互不影响

三、类锁

类锁用于保护类级别的资源(如静态变量),确保同一时刻只有一个线程能访问被锁定的静态资源。

1. 锁定静态方法

java 复制代码
public static synchronized void add() {
    shareField++;
    System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
}

synchronized 修饰静态方法时,锁的是类的 Class 对象。

2. 锁定 class 对象

java 复制代码
public void add() {
    synchronized (SynchronizedTest.class) {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
}

3. 锁定静态实例变量

java 复制代码
private static final Object obj = new Object();
public void add() {
    synchronized (obj) {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
}
类锁特点
  • 锁对象:类的 Class 对象或静态实例变量
  • 所有实例共享同一把锁,实现全局互斥

四、对象锁与类锁的区别

选择对象锁还是类锁,取决于需要保护的变量是实例级还是类级(静态)。

例如:

java 复制代码
public class SynchronizedTest {
    private static int shareField = 0;
    public void add() {
        synchronized (this) {
            shareField++;
            System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
        }
    }
    public static void main(String[] args) {
        new Thread(() -> {
            SynchronizedTest sync1 = new SynchronizedTest();
            for (int n = 0; n < 100000; n++) {
                sync1.add();
            }
        }).start();
        new Thread(() -> {
            SynchronizedTest sync2 = new SynchronizedTest();
            for (int n = 0; n < 100000; n++) {
                sync2.add();
            }
        }).start();
    }
}

上述代码中,两个线程分别操作不同实例,但都修改静态变量 shareField。此时对象锁无法保证线程安全,需使用类锁:

java 复制代码
public void add() {
    synchronized (SynchronizedTest.class) {
        shareField++;
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
    }
}

五、总结

特性 对象锁 类锁
锁对象 当前实例(this)/obj 类的Class对象/静态实例变量
作用范围 同一实例间互斥 所有实例间互斥
适用场景 保护实例级变量 保护类级变量(静态变量)
并发影响 不同实例间无互斥 所有实例共享同一把锁
实现方式 synchronized方法/代码块 static synchronized方法/class锁对象

合理选择锁的类型,是实现高效并发和线程安全的关键。

相关推荐
Jm_洋洋2 分钟前
【Linux系统编程】程序替换:execve(execl、execlp、execle、execv、execvp、execvpe)
linux·运维·c语言·开发语言·程序人生
CodeCraft Studio6 分钟前
国产化Word处理控件Spire.Doc教程:用Java实现TXT文本与Word互转的完整教程
java·c#·word·spire.doc·word文档转换·txt转word·word转txt
徐子童12 分钟前
数据结构---优先级队列(堆)
java·数据结构·面试题·优先级队列··topk问题
滑水滑成滑头17 分钟前
**标题:发散创新:智能交通系统的深度探究与实现**摘要:本文将详细
java·人工智能·python
冯诺依曼的锦鲤24 分钟前
算法练习:前缀和专题
开发语言·c++·算法
siriuuus31 分钟前
Maven 核心概念及生命周期
java·maven
闭着眼睛学算法36 分钟前
【双机位A卷】华为OD笔试之【哈希表】双机位A-跳房子I【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
java·c语言·c++·python·算法·华为od·散列表
JinSoooo42 分钟前
pnpm monorepo 联调:告别 --global 参数
开发语言·javascript·ecmascript·pnpm
孔明兴汉1 小时前
Cursor MCP 第一章-第一节-MCP协议简介.md
java·ai
信仰_2739932431 小时前
枚举类Enum反编译后效果
java·开发语言