Discuss / Java / 为什么说“不可变对象无需同步”呢?

为什么说“不可变对象无需同步”呢?

Topic source

Sefank

#1 Created at ... [Delete] [Delete and Lock User]

比如说下面这个例子,str虽然是不可变的String,但不给write()加锁还是会出现read()三次读取的字符不是来自同一个字符串吧?

import java.util.concurrent.atomic.AtomicBoolean;

class SharedList {
    volatile String str = "   ";
    AtomicBoolean state = new AtomicBoolean(false);

    void write() {
        while (true) {
            if (state.compareAndSet(false, true)) {
                str = "abc";
            } else if (state.compareAndSet(true, false)) {
                str = "123";
            }
        }
    }

    void read() {
        while (true) {
            synchronized (str) {
                System.out.print(str.charAt(0) + " ");
                System.out.print(str.charAt(1) + " ");
                System.out.println(str.charAt(2));
            }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        SharedList sharedList = new SharedList();
        new Thread(sharedList::write).start();
        new Thread(sharedList::read).start();
    }
}

adong660

#2 Created at ... [Delete] [Delete and Lock User]

个人理解,廖老师的例子可能不是很恰当。

“不可变对象”通常是指创建之后状态一定不会再发生改变的对象(它里面的引用是final,引用的对象是不可变对象,而且没有setter等方法)。例如

class MyClass {
    final String str;
    MyClass(String str) {this.str = str;}
    String getStr() {return str;}
}

那么这个Myclass类的对象就是“不可变对象”。显然,这样的对象一经创建就固定下来了,只能读不能写,用户类当然可以随意使用,不需要再做同步。

但是在下面廖老师的例子中,

class Data {
    List<String> names;
    void set(String[] names) {
        this.names = List.of(names);
    }
    List<String> get() {
        return this.names;
    }
}

Data类并不是不可变的。虽然这里实例变量names所引用的对象是不可变的(由set方法保证),但是names这个引用是可变的。之所以这个类的set和get无需同步,与其说是因为“names所指向的对象是不可变的”,不如说是因为this.names = ...;和return this.names;都是原子操作。只要这里不只有names一个变量要set和get,它就不是线程安全的了。

当然,即便一个类不是不可变的,如果它的变量所引用的对象都是不可变的,还是可以减轻多线程编程的负担,因为这样就只需要保证“写引用、读引用及其对象”这两种操作是线程安全的就行了。你的例子之所以不是线程安全的,就是因为write和read方法没有对str这个引用的读写做同步。在线程A执行read时,如果线程B插进来要写str,此时A进行了几次读取是不确定的,B写完之后A再读,就会出问题。为了实现线程安全,就要做同步,保证read的一系列读操作不会被别的线程打断就可以了。


  • 1

Reply