第三部分-并发设计模式28:Immutability

1.什么是Immutability

Immutability,不变性,
叫做不变性设计模式,简单来说就是对象一旦创建,状态就不再发生变化。
变量一旦被赋值,就不允许修改了(没有写操作);没有修改操作,就保持了不变性

2.什么情况用Immutablity设计模式

多个线程同时读写同一个共享变量存在并发问题,核心条件是读写,如果只有读,没有写,是没有并发问题的
解决并发问题,最简单的办法就是让共享变量只有读操作,没有写操作。

3.快速实现具备不可变的类

将一个雷的所有属性都设置为final,并且只允许存在只读方法,那么这个类基本上就具备不可变性了。并且这个类本身也是final的,这个类本身不允许继承。

4.jdk中使用Immutablity设计模式的,不可变的类

Long,String


public final class String {
  private final char value[];
  // 字符替换
  String replace(char oldChar, 
      char newChar) {
    //无需替换,直接返回this  
    if (oldChar == newChar){
      return this;
    }

    int len = value.length;
    int i = -1;
    /* avoid getfield opcode */
    char[] val = value; 
    //定位到需要替换的字符位置
    while (++i < len) {
      if (val[i] == oldChar) {
        break;
      }
    }
    //未找到oldChar,无需替换
    if (i >= len) {
      return this;
    } 
    //创建一个buf[],这是关键
    //用来保存替换后的字符串
    char buf[] = new char[len];
    for (int j = 0; j < i; j++) {
      buf[j] = val[j];
    }
    while (i < len) {
      char c = val[i];
      buf[i] = (c == oldChar) ? 
        newChar : c;
      i++;
    }
    //创建一个新的字符串返回
    //原字符串不会发生任何变化
    return new String(buf, true);
  }
}

String中的可变方法,往往是新new 出一个新不可变对象来实现,会不会浪费内存呢?会的

5.如何解决内存浪费,使用享元模式

Long,Integer,Short,Byte 等这些基本数据类型的包装类都使用了享元模式

Long使用享元模式的范例(本质上是一个对象池或者缓存池的概念)


Long valueOf(long l) {
  final int offset = 128;
  // [-128,127]直接的数字做了缓存
  if (l >= -128 && l <= 127) { 
    return LongCache
      .cache[(int)l + offset];
  }
  return new Long(l);
}
//缓存,等价于对象池
//仅缓存[-128,127]直接的数字
static class LongCache {
  static final Long cache[] 
    = new Long[-(-128) + 127 + 1];

  static {
    for(int i=0; i<cache.length; i++)
      cache[i] = new Long(i-128);
  }
}

String,Integer类也是类似

6.使用享元模式的这些包装类为什么不适合用于锁?

是因为有些看起来像是私有的锁,其实是共有的

伪代码,看着像是两把锁,其实是同一把锁


class A {
  Long al=Long.valueOf(1);
  public void setAX(){
    synchronized (al) {
      //省略代码无数
    }
  }
}
class B {
  Long bl=Long.valueOf(1);
  public void setBY(){
    synchronized (bl) {
      //省略代码无数
    }
  }
}

7.Immutability模式注意事项

  • 对象的所有属性都是final的,并不能保证不可变性
  • 不可变对象也需要正确发布
    final修饰的普通对象,对象属性是可以被修改的

8.正确使用Immutability的姿势

public final class ServerConfig {

    private final int masterExecThreads = 100;
    private final int masterExecTaskNum = 20;
    private final int listenPort = 5678;
    private final String address = NetUtils.getAddr(listenPort);

    public String getAddress() {
        return address;
    }

    public int getMasterExecThreads() {
        return masterExecThreads;
    }

    public int getMasterExecTaskNum() {
        return masterExecTaskNum;
    }

    public int getListenPort() {
        return listenPort;
    }
}
posted @ 2021-06-01 17:22  SpecialSpeculator  阅读(112)  评论(0编辑  收藏  举报