transient
vsvolatile
不同之处volatile
和序列化无关,写数据到改修饰的变量,会同步刷新到内存中,访问变量时从内存中读取,与synchronized
块相比,volatile
变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是synchronized
的一部分,不具备原子性。只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
1.对变量的写操作不依赖于当前值
2.该变量没有包含在具有其他变量的不变式中第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性
如果凑巧两个线程在同一时间使用不一致的值执行 setLower 和 setUpper 的话,则会使范围处于不一致的状态。例如,如果初始状态是 (0, 5),同一时间内,线程 A 调用 setLower(4) 并且线程 B 调用 setUpper(3),显然这两个操作交叉存入的值是不符合条件的,那么两个线程都会通过用于保护不变式的检查,使得最后的范围值是 (4, 3) —— 一个无效值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19@NotThreadSafe
public class NumberRange {
private int lower, upper;
public int getLower() { return lower; }
public int getUpper() { return upper; }
public void setLower(int value) {
if (value > upper)
throw new IllegalArgumentException(...);
lower = value;
}
public void setUpper(int value) {
if (value < lower)
throw new IllegalArgumentException(...);
upper = value;
}
}正确使用volatile模式
状态标志,公共特性是:通常只有一种状态转换;shutdownRequested 标志从 false 转换为 true,然后程序停止
1
2
3
4
5
6
7
8
9volatile boolean shutdownRequested;
...
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
序列化会排除被
transient
修饰的变量,反序列化会返回相应的默认值
Java 小知识
关注微信公众号
帅哥美女们,请赐予我力量吧!
- 本文链接: http://willkernel.github.io/2018/04/02/Java-小知识/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!