Java锁总览:
乐观锁:无锁编程,使用数据版本比较的方法来保证安全性,使用CAS(Compare And Swap)机制。乐观锁假设在大多数情况下不会发生冲突,因此在执行操作时不会加锁,而是在更新数据时检查是否有其他线程修改了数据。
悲观锁:通过synchronized关键字实现。悲观锁假设在任何时候都可能发生冲突,因此在执行操作前会先加锁,以确保数据的一致性。
自旋锁:同样基于CAS机制。自旋锁在尝试获取锁失败后,不会立即进入阻塞状态,而是循环等待一段时间,直到成功获取锁。
可重入锁:由synchronized关键字、ReentrantLock和Lock接口实现。可重入锁允许同一个线程多次获取同一把锁,而不会出现死锁的情况。
读写锁:通过ReentrantReadWriteLock实现。读写锁分为读锁和写锁,允许多个线程同时进行读操作,但写操作是独占的。
公平锁:通过ReentrantLock(true)实现。公平锁保证线程按照请求锁的顺序来获取锁,避免饥饿现象。
非公平锁:通过synchronized关键字和ReentrantLock(false)实现。非公平锁不保证线程获取锁的顺序,可能会导致某些线程长期得不到锁。
共享锁:在ReentrantReadWriteLock中用于读操作。共享锁允许多个线程同时持有读锁,但不允许写操作。
独占锁(排他锁、互斥锁、同步锁):通过synchronized关键字以及ReentrantReadWriteLock中的写锁实现。独占锁在同一时间只允许一个线程持有锁。
重量级锁:由synchronized关键字实现。重量级锁在Java早期版本中会导致线程挂起和唤醒的开销较大,但在JDK 1.6及以后版本中进行了优化。
轻量级锁和偏向锁:属于锁优化技术,用于减少锁的竞争和提升性能。轻量级锁在没有竞争的情况下使用,偏向锁则偏向于让一个线程长时间持有锁。
锁粗化和锁消除:都是锁优化技术,锁粗化是指将短时间的锁合并为长时间的锁,以减少锁的开销;锁消除则是指编译器自动识别并移除不必要的锁操作。
关键字介绍:
CAS(Compare And Swap):
这是一种硬件指令级别的操作,用于实现乐观锁。它不使用锁,而是通过比较预期值与当前值是否相同来决定是否更新数据。如果不同,则说明数据已经被其他线程修改过,需要重新尝试。
private AtomicInteger atomicValue = new AtomicInteger(0);
public void incrementValue() {
int expectedValue;
int newValue;
do {
// 获取当前值
expectedValue = atomicValue.get();
// 计算新值
newValue = expectedValue + 1;
// 使用CAS尝试更新值
} while (!atomicValue.compareAndSet(expectedValue, newValue));
System.out.println("Updated Value: " + atomicValue.get());
}
@Test
public void CAS() {
incrementValue(); // 输出:Updated Value: 1
}
synchronized:synchronized关键字-可用于代码块和方法
是Java中的一种同步机制,可以视为悲观锁。
可重入锁:允许同一个线程多次获取同一把锁。
非公平锁:非公平锁允许插队,而公平锁则按照请求的顺序分配锁。
独占锁/互斥锁:意味着在任何时刻只能有一个线程持有该锁。
重量级锁:相对于轻量级锁而言,它涉及到操作系统层面的调度,开销较大。
private int counter = 0; //假设这是共享资源
private final Object lock = new Object(); // 定义一个锁对象 给synchronized代码块用
//synchronized代码块
public void incrementCounterBlock() {
synchronized (lock) { // 锁定在特定对象上
counter++;
System.out.println("Counter incremented to: " + counter);
}
}
//synchronized方法
public synchronized void incrementCounterMethod() {
counter++;
System.out.println("Counter incremented to: " + counter);
}
//模拟多线程操作
@Test
public void synchronizedTest() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
//incrementCounterMethod();也行
incrementCounterBlock();
try {
// 让当前线程短暂休眠,模拟实际工作并允许其他线程运行
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
//incrementCounterMethod();也行
incrementCounterBlock();
try {
// 让当前线程短暂休眠,模拟实际工作并允许其他线程运行
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
// 等待所有线程完成
t1.join();
t2.join();
System.out.println("Final Counter Value: " + counter);
}
ReentrantLock:ReentrantLock.lock()和ReentrantLock.unlock(),创建ReentrantLock对象时,true为公平锁,false为非公平锁
可重入锁:同synchronized一样,支持同一个线程多次获取同一把锁。
构造函数参数ReentrantLock(boolean fair):当参数为true时,表示创建一个公平锁;false时,默认创建的是非公平锁。
private int counter = 0; // 共享资源
private final Lock lock = new ReentrantLock(true); // 创建一个ReentrantLock实例
public void incrementCounter() {
lock.lock(); // 获取锁
try {
counter++;
System.out.println(Thread.currentThread().getName() + " incremented counter to: " + counter);
} finally {
lock.unlock(); // 确保在操作完成后释放锁
}
}
@Test
public void lockTest() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
incrementCounter();
try {
// 模拟实际工作负载
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
incrementCounter();
try {
// 模拟实际工作负载
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
}
});
t1.start();
t2.start();
// 等待所有线程完成
t1.join();
t2.join();
System.out.println("Final Counter Value: " + counter);
}
ReentrantReadWriteLock:
读写锁:允许多个读操作并发执行,但写操作是独占的。
共享锁(读操作):允许多个线程同时读取资源。
独占锁(写操作):确保在进行写操作时没有其他线程可以访问该资源。
@Autowired
private ProjectMapper projectMapper;
//用于创建 读锁对象、写锁对象
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//创建 读锁对象
private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
//创建写锁对象
private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
public Project getProjectById(Long id) {
readLock.lock();
try {
return projectMapper.getProjectById(id);
} finally {
readLock.unlock();
}
}
public List<Project> getAllProjects() {
readLock.lock();
try {
return projectMapper.getAllProjects();
} finally {
readLock.unlock();
}
}
@Transactional
public void insertProject(Project project) {
writeLock.lock();
try {
projectMapper.insertProject(project);
} finally {
writeLock.unlock();
}
}
@Transactional
public boolean updateProject(Project project) {
writeLock.lock();
try {
int affectedRows = projectMapper.updateProject(project);
if (affectedRows == 0) {
System.out.println("Optimistic locking failed");
return false;
}
return true;
} finally {
writeLock.unlock();
}
}
使用 ReentrantReadWriteLock 的读锁(ReadLock)和写锁(WriteLock)是为了控制对共享资源的并发访问。读锁允许多个线程同时持有,只要没有写操作正在进行;而写锁是独占的,当一个线程获取了写锁时,其他任何读或写操作都必须等待。
170万+

被折叠的 条评论
为什么被折叠?



