Java并发编程中的原子性与锁机制
立即解锁
发布时间: 2025-08-22 00:36:51 阅读量: 1 订阅数: 4 


Java安全编码指南与最佳实践
### Java并发编程中的原子性与锁机制
#### 1. 并发集合与原子性
在Java并发编程中,`ConcurrentHashMap`是一个重要的并发集合。它返回的迭代器是弱一致性的,而非快速失败的。这意味着在迭代过程中,它能容忍并发修改,遍历的是迭代器创建时的元素,并且可能(但不保证)反映迭代器创建后集合的修改。同时,为了性能考虑,`ConcurrentHashMap.size()`和`ConcurrentHashMap.isEmpty()`等方法允许返回近似结果,因此在需要精确结果的代码中应避免依赖这些返回值。
如果未能确保多个操作作为一个原子操作执行,在多线程应用中可能会导致竞态条件。以下是相关规则的风险评估表格:
| 规则 | 严重程度 | 可能性 | 修复成本 | 优先级 | 级别 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| VNA03 - J | 低 | 可能 | 中等 | P4 | L3 |
#### 2. 链式方法调用的原子性
方法链式调用是一种方便的机制,允许在单个语句中对同一对象进行多次方法调用。然而,尽管链式调用中的每个方法可能是原子的,但整个链式调用本身是非原子的。因此,调用链式方法的代码必须提供足够的锁来保证整个调用链是原子的。
##### 2.1 非合规代码示例
以下是一个使用JavaBeans模式的非线程安全的代码示例:
```java
final class USCurrency {
// Change requested, denomination (optional fields)
private int quarters = 0;
private int dimes = 0;
private int nickels = 0;
private int pennies = 0;
public USCurrency() {}
// Setter methods
public USCurrency setQuarters(int quantity) {
quarters = quantity;
return this;
}
public USCurrency setDimes(int quantity) {
dimes = quantity;
return this;
}
public USCurrency setNickels(int quantity) {
nickels = quantity;
return this;
}
public USCurrency setPennies(int quantity) {
pennies = quantity;
return this;
}
}
// Client code:
class exampleClientCode {
private final USCurrency currency = new USCurrency();
// ...
public exampleClientCode() {
Thread t1 = new Thread(new Runnable() {
@Override public void run() {
currency.setQuarters(1).setDimes(1);
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override public void run() {
currency.setQuarters(2).setDimes(2);
}
});
t2.start();
//...
}
}
```
在这个示例中,由于JavaBeans模式不是线程安全的,当对象被并发修改时,可能会导致对象状态不一致。
##### 2.2 合规解决方案
使用Builder模式可以确保对象创建的线程安全性和原子性:
```java
final class USCurrency {
private final int quarters;
private final int dimes;
private final int nickels;
private final int pennies;
public USCurrency(Builder builder) {
this.quarters = builder.quarters;
this.dimes = builder.dimes;
this.nickels = builder.nickels;
this.pennies = builder.pennies;
}
// Static class member
public static class Builder {
private int quarters = 0;
private int dimes = 0;
private int nickels = 0;
private int pennies = 0;
public static Builder newInstance() {
return new Builder();
}
private Builder() {}
// Setter methods
public Builder setQuarters(int quantity) {
this.quarters = quantity;
return this;
}
public Builder setDimes(int quantity) {
this.dimes = quantity;
return this;
}
public Builder setNickels(int quantity) {
this.nickels = quantity;
return this;
}
public Builder setPennies(int quantity) {
this.pennies = quantity;
return this;
}
public USCurrency build() {
return new USCurrency(this);
}
}
}
// Client code:
class exampleClientCode {
private volatile USCurrency currency;
// ...
public exampleClientCode() {
Thread t1 = new Thread(new Runnable() {
@Override public void run() {
currency = USCurrency.Builder.newInstance().
setQuarters(1).setDimes(1).build();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override public void run() {
currency = USCurrency.Builder.newInstance().
setQuarters(2).setDimes(2).build();
}
});
t2.start();
//...
}
}
```
Builder模式通过`newInstance()`方法获取Builder实例,使用setter方法设置可选参数,最后调用`build()`方法完成对象构建,使`USCurrency`类成为不可变类,从而保证线程安全。
#### 3. 64位值读写的原子性
J
0
0
复制全文
相关推荐










