• Jialin
    2019-05-02
    根据文章内容,一个类具备不可变属性需要满足"类和属性都必须是 final 的,所有方法均是只读的",类的属性如果是引用型,该属性对应的类也需要满足不可变类的条件,且不能提供修改该属性的方法,
    Account类的唯一属性user是final的,提供的方法是可读的,user的类型是StringBuffer,StringBuffer也是final的,这样看来,Account类是不可变性的,但是去看StringBuffer的源码,你会发现StringBuffer类的属性value是可变的<String类中的value定义:private final char value[];StringBuffer类中的value定义:char[] value;>,并且提供了append(Object object)和setCharAt(int index, char ch)修改value.
    所以,Account类不具备不可变性
    展开
     2
     48
  • 榣山樵客™
    2019-05-05
    这段代码应该是线程安全的,但它不是不可变模式。StringBuffer只是字段引用不可变,值是可以调用StringBuffer的方法改变的,这个需要改成把字段改成String这样的不可变对象来解决。

    作者回复: 👍

     1
     27
  • 张天屹
    2019-05-05
    具不具备不可变性看怎么界定边界了,类本身是具备的,StrnigBuffer的引用不可变。但是因为StringBuffer是一个对象,持有非final的char数组,所以底层数组是可变的。但是StringBuffer是并发安全的,因为方法加锁synchronized
    
     9
  • 拯救地球好累
    2019-07-28
    ---总结---
    1. 不可变类的特点:类、属性都是final的,方法是只读的
    2. 为了解决有些不可变类每次创建一个新对象导致内存浪费的问题:享元模式/对象池
    3. 注意事项:区别引用不可变和实际内容不可变
    4. 更简单的不可变对象:无状态对象

    作者回复: 👍

    
     8
  • 对象正在输入...
    2019-05-05
    不可变类的三个要求 : 类和属性都是 final 的,所有方法均是只读的
    这里的StringBuffer传进来的只是个引用,调用方可以修改,所以这个类不具备不可变性。

     1
     6
  • Hour
    2019-06-01
    //Foo 线程安全
    final class Foo{
      final int age=0;
      final int name="abc";
    }
    //Bar 线程不安全
    class Bar {
      Foo foo;
      void setFoo(Foo f){
        this.foo=f;
      }
    }
    老师好,对foo的引用和修改在多线程环境中并不能保证原子性和可见性,这句话怎么理解,能用具体的例子说明一下吗?
    展开
    
     4
  • 炎炎
    2019-05-24
    这个专栏一直看到这儿,真的很棒,课后问题也很好,让我对并发编程有了一个整体的了解,之前看书一直看不懂,老师带着梳理一遍,看书也容易多了,非常感谢老师,希望老师再出专栏

    作者回复: 感谢一路相伴😄

    
     2
  • 水滴s
    2019-12-12
    老师,问下 Bar这个类的foo属性的设值在多线程下为什么会有原子性问题,我理解的只会有可见性问题?

    作者回复: 严格讲你是对的,仅仅是设置属性这个操作不涉及原子性。只有类似foo=new Foo(),这种组合操作时才会有原子性问题,这时候的原子性出在foo的属性上,而不是bar的属性foo上。对象赋值的原子性问题一般都是因为组合操作。

    
     1
  • 叶十七
    2019-10-13
    关于final的理解
    1. 域并不是都需要定义为final才能线程安全,只要是私有的并且只读,也能保证线程安全
    2.类被继承,那么实际上是子类不一定安全,和当前这个类无关,如果当前类是安全的,用不用final修饰都是安全的
    3.final修饰容器类,对象时,引用不可变,兑现内容可变,也不能保证线程安全。

    Java 并发编程实战中对final的描述个人感觉不是那么准确。
    展开
    
     1
  • gogo
    2019-05-13
    final StringBuffer user;

    StingBuffer 是 引用 类型, 当我们说它final StingBuffer user 不可变时,实际上说的是它user指向堆内存的地址不可变, 但堆内存的user对象,通过sub append 方法实际是可变的……

    作者回复: 👍

    
     1
  • rayjun
    2019-05-05
    不是不可变的,user 逃逸了
    
     1
  • 南山
    2019-05-03
    不具备,stringbuffer本身线程不安全
     1
     1
  • 张三
    2019-05-03
    打卡。
    
     1
  • QQ怪
    2019-05-02
    不具备不可变性,原因是stringbuffer类存在更改user对象方法
    
     1
  • 发条橙子 。
    2019-05-02
    老师五一节日快乐。

    思考题 :
    不可变类的三要素 :类、属性、方法都是不可变的。 思考题这个类虽然是final ,属性也是final并且没有修改的方法 , 但是 stringbuffer这个属性的内容是可变的 , 所以应该没有满足三要素中的属性不可变 , 应该不属于不可变类 。


    另外老师我有个问题想问下, 我看jdk一些源码里,也用了对象做锁。 例如 我有个变量 final ConcurrentHashMap cache , 有些方法中会对 cache变量 put新的值 , 但是还有用这个对象做 synchronized(cache) 对象锁 , 这种做法对么? 如果对的话,是因为管程只判断对象的首地址没有改变的原因么 ,希望老师指点一下😁
    展开

    作者回复: 感谢感谢😂
    你的问题有点笼统,jdk也不是没有bug,sync的锁是记在对象头里的

    
     1
  • 钱高明
    2020-01-17
    这文章应该主要讲讲不可变数据结构
    
    
  • Joker
    2019-11-07
    不具备不可变性的,嘻嘻。
    
    
  • Neo
    2019-10-28
    Integer,Long,Double等数值类型的数据不适合用来做锁,其实是不能用xxx.valueOf方法生成的对象作为锁,因为只有valueOf方法才会返回缓存中的数据,直接new出来的对象是没有这个问题的。
     1
    
  • hout
    2019-10-16
    "下面我们再看看如何正确地发布不可变对象。不可变对象虽然是线程..."

    疑问: 这段后面怎么没有提正确发布的情况呢
    
    
  • Sharry
    2019-09-27
    太棒了, 又学到了

    以前只知道 String 是 final 类型的, 但总是无法很好的解释这个问题, 学习了本篇的课程, 让我了解到了不可变模式的妙用, 原来这样是实现线程安全的手段, 巧妙!
    
    
我们在线,来聊聊吧