锁是Java多线程编程中用于控制线程对共享资源访问的同步机制,主要目的是解决线程安全问题,保证数据的一致性和完整性。
一、锁的基本概念
锁的本质是一种线程同步机制,它规定了3大特性:
互斥性:同一时刻只有一个线程能持有锁
可见性:锁的获取和释放保证了对共享变量的修改对其他线程可见
有序性:防止指令重排序导致的并发问题 二、Java锁的主要分类
1. 按实现方式分
(1) 内置锁:顾名思义就是内置在代码里的,使用的时候看不到的锁,主要为synchronized,实现如下:
// 实例方法锁
public synchronized void method() {}
// 静态方法锁
public static synchronized void method() {}
// 代码块锁
public void method() {
synchronized(lockObject) {
// 临界区
}
}
(2) 显式锁:与隐式锁不同,其就是使用时可以被看见的锁,主要为lock,案例如下
Lock lock = new ReentrantLock();
lock.lock();
try {
// 临界区
} finally {
lock.unlock();
}
根据类型,锁又可以分为如下几种:
锁类型 | 特点描述 |
---|---|
可重入锁 | 同一线程可多次获取同一把锁 |
公平锁 | 按申请顺序分配锁 |
非公平锁 | 不保证申请顺序,可能插队 |
读写锁 | 读读共享,读写/写写互斥 |
乐观锁 | 假设无冲突,失败时重试 |
悲观锁 | 假设会发生冲突,先加锁再操作 |
三、锁的使用建议
选择原则:简单场景优先用synchronized;需要高级功能时用ReentrantLock;读多写少用ReadWriteLock/StampedLock
注意事项:避免锁粒度过大(性能差)或过小(易死锁);锁代码块而不是整个方法;确保锁一定会被释放(finally块);注意锁的可重入次数避免溢出
性能优化:减少锁持有时间;降低锁粒度(如分段锁);读写分离
锁是Java并发编程的基石,理解各种锁的特性和适用场景,才能编写出既安全又高效的多线程程序。