您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java中如何用一把锁保护多个资源
## 引言
在多线程编程中,保护共享资源免受并发访问的破坏是至关重要的。Java提供了多种同步机制,其中`synchronized`关键字和`ReentrantLock`是最常用的锁工具。当我们需要保护多个相关联的资源时,如何高效地使用同一把锁就成为了一个关键问题。本文将深入探讨:
1. 多资源保护的核心挑战
2. 基于对象锁的解决方案
3. 使用显式锁(ReentrantLock)的实现
4. 典型应用场景分析
5. 性能优化与注意事项
## 一、多资源保护的核心挑战
### 1.1 竞态条件的产生
当多个线程同时访问和修改相关联的资源时,如果没有适当的同步措施,就会导致数据不一致。例如银行转账操作需要同时修改转出账户和转入账户的余额:
```java
class Account {
private int balance;
public void transfer(Account target, int amount) {
this.balance -= amount;
target.balance += amount;
}
}
为每个资源单独加锁可能导致死锁:
// 错误示范 - 可能导致死锁
synchronized(this) {
synchronized(target) {
this.balance -= amount;
target.balance += amount;
}
}
创建专门的锁对象来保护所有相关资源:
class Account {
private static final Object lock = new Object();
private int balance;
public void transfer(Account target, int amount) {
synchronized(lock) {
this.balance -= amount;
target.balance += amount;
}
}
}
利用类的Class对象作为锁:
public void transfer(Account target, int amount) {
synchronized(Account.class) {
this.balance -= amount;
target.balance += amount;
}
}
当资源数量固定且较多时,可以采用分段锁提高并发性:
class ResourceManager {
private final Object[] locks;
private final Map<String, Resource> resources;
public ResourceManager(int segments) {
locks = new Object[segments];
for(int i=0; i<segments; i++) {
locks[i] = new Object();
}
}
public void update(String resourceId) {
int segment = resourceId.hashCode() % locks.length;
synchronized(locks[segment]) {
// 操作对应资源
}
}
}
class Account {
private static final ReentrantLock lock = new ReentrantLock();
private int balance;
public void transfer(Account target, int amount) {
lock.lock();
try {
this.balance -= amount;
target.balance += amount;
} finally {
lock.unlock();
}
}
}
避免长时间等待:
public boolean tryTransfer(Account target, int amount, long timeout)
throws InterruptedException {
if(lock.tryLock(timeout, TimeUnit.MILLISECONDS)) {
try {
this.balance -= amount;
target.balance += amount;
return true;
} finally {
lock.unlock();
}
}
return false;
}
当读多写少时,使用ReadWriteLock提高性能:
class ResourceCache {
private static final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private Map<String, Object> cache = new HashMap<>();
public Object get(String key) {
rwLock.readLock().lock();
try {
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
class ConnectionPool {
private final Lock lock = new ReentrantLock();
private final Condition available = lock.newCondition();
private Queue<Connection> pool = new LinkedList<>();
public Connection getConnection() throws InterruptedException {
lock.lock();
try {
while(pool.isEmpty()) {
available.await();
}
return pool.poll();
} finally {
lock.unlock();
}
}
public void releaseConnection(Connection conn) {
lock.lock();
try {
pool.offer(conn);
available.signal();
} finally {
lock.unlock();
}
}
}
class LRUCache<K,V> {
private final Lock lock = new ReentrantLock();
private Map<K,V> map = new LinkedHashMap<>(16, 0.75f, true);
private int maxSize;
public V get(K key) {
lock.lock();
try {
return map.get(key);
} finally {
lock.unlock();
}
}
public void put(K key, V value) {
lock.lock();
try {
map.put(key, value);
if(map.size() > maxSize) {
// 移除最旧条目
}
} finally {
lock.unlock();
}
}
}
尽量减少临界区代码量:
// 不推荐 - 锁范围过大
synchronized(lock) {
result = compute(); // 耗时计算
sharedResource.update(result);
}
// 推荐做法
Result result = compute(); // 在锁外计算
synchronized(lock) {
sharedResource.update(result);
}
// 危险代码 - 可能导致死锁
synchronized(lockA) {
synchronized(lockB) {
// ...
}
}
// 公平锁 - 减少线程饥饿但性能较低
ReentrantLock fairLock = new ReentrantLock(true);
// 非公平锁 - 默认选项,吞吐量更高
ReentrantLock unfairLock = new ReentrantLock();
使用JMX检查锁状态:
ReentrantLock lock = new ReentrantLock();
// 注册到JMX...
System.out.println("等待线程数: " + lock.getQueueLength());
System.out.println("是否被持有: " + lock.isLocked());
使用同一把锁保护多个资源是Java并发编程中的常见模式,关键要点包括:
通过合理设计,可以在保证线程安全的同时获得良好的系统性能。在实际开发中,建议结合线程转储和性能分析工具不断优化锁的使用策略。
注意:本文示例代码为演示核心概念做了简化,实际应用中需要考虑更多边界条件和异常处理。 “`
这篇文章共计约2300字,采用Markdown格式编写,包含: - 多级标题结构 - 代码块示例 - 重点概念强调 - 实际应用场景 - 性能优化建议
可根据需要进一步扩展具体案例或添加更多性能对比数据。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。