在计算机科学中,锁是一种同步机制,用于控制多个线程或进程对共享资源(如数据)的访问,以防止数据竞态和确保数据一致性。在Java中,锁的概念主要体现在多线程环境下,用于解决并发编程中的同步问题。
Java中有几种不同类型的锁:
1、内部锁 (Intrinsic Locks)或监视器锁 (Monitor Locks):
-
这些锁通过使用synchronized关键字来获得。每个Java对象都有一个内部锁,当一个线程进入一个实例方法或块时,它会自动获取该对象的锁。
-
如果方法是static的,则它取得的是类对象对应的锁。
-
示例代码:
public class Counter {private int count = 0;// 使用内部锁的同步方法public synchronized void increment() {count++;}// 使用内部锁的同步代码块public void decrement() {synchronized(this) {count--;}}}
2、显式锁 (Explicit Locks):
-
在java.util.concurrent.locks包中提供了更复杂的锁机制,例如ReentrantLock,允许更灵活的锁管理。
-
ReentrantLock支持重入,意味着已经拥有该锁的线程可以再次获取锁而不会被阻塞。
-
示例代码:
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Counter {private final Lock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}}
3、读/写锁 (Read-Write Locks):
-
例如ReentrantReadWriteLock,允许多个线程同时读取,但只允许一个线程进行写入。
-
它包含一对锁:一个读锁和一个写锁,通过分离读和写操作来提高性能。
-
示例代码:
import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class SharedDataStructure {private final ReadWriteLock rwLock = new ReentrantReadWriteLock();private final Lock readLock = rwLock.readLock();private final Lock writeLock = rwLock.writeLock();private int data = 0;public void writeData(int newData) {writeLock.lock();try {data = newData;} finally {writeLock.unlock();}}public int readData() {readLock.lock();try {return data;} finally {readLock.unlock();}}}
4、乐观锁/Optimistic Locks和悲观锁/Pessimistic Locks
乐观锁(Optimistic Locks)
乐观锁假设多个事务同时对同一条记录进行编辑的几率很低,因此它不会立即锁定数据。相反,当事务提交时,通过比较数据版本来检查在读取数据后是否有其他事务进行了修改。
Java中通常使用版本号或时间戳字段来实现乐观锁。例如,在JPA中,你可以使用@Version注解来标记一个字段作为版本控制:
import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Version;public class ExampleEntity {private Long id;private Integer version;// getters and setters ...}
悲观锁(Pessimistic Locks)
import javax.persistence.LockModeType;import javax.persistence.EntityManager;ExampleEntity entity = entityManager.find(ExampleEntity.class, entityId, LockModeType.PESSIMISTIC_WRITE);
当使用PESSIMISTIC_WRITE时,JPA将使用相应的数据库锁,如SQL的SELECT FOR UPDATE语句,直到当前事务完成后才释放锁。
总结
-
这些不是Java语言结构,而是基于不同策略实现锁机制的概念。
-
乐观锁通常用在没有严格同步要求的场景中,并假设冲突很少发生。常见的实现方式有版本号等。
-
悲观锁假设冲突很常见,因此总是先加锁。数据库事务中的锁机制就是一个例子。
5、条件锁 (Condition Locks):
-
条件锁允许线程之间有更细粒度的协作。与ReentrantLock一起使用,一个锁可以有一个或多个条件对象。
-
这些条件对象可以控制线程在某个特定状态下暂停执行(await),直到另一个线程在该条件上发送信号(signal)或广播(signalAll)后才继续执行。
-
示例代码:
public class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();final Condition notEmpty = lock.newCondition();final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();try {while (count == items.length)notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();} finally {lock.unlock();}}public Object take() throws InterruptedException {lock.lock();try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;} finally {lock.unlock();}}}
本篇文章来源于微信公众号: 互联网面试小帮手
微信扫描下方的二维码阅读本文

Comments NOTHING