Java 小知识

  • transient vs volatile不同之处

    • 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
      9
       volatile boolean shutdownRequested;
      ...
      public void shutdown() { shutdownRequested = true; }

      public void doWork() {
      while (!shutdownRequested) {
      // do stuff
      }
      }
    • 其他待续

  • 序列化会排除被transient修饰的变量,反序列化会返回相应的默认值

willkernel wechat
关注微信公众号
帅哥美女们,请赐予我力量吧!