用于多线程系统的 Java 不可变对象(immutable对象)。我做错了什么?

标签 java multithreading concurrency immutability

我有点不了解不可变对象(immutable对象)。我的想法是它们在多线程环境中很有用,而且根据定义是线程安全的。

但下面的代码似乎恰恰相反!

public class ImmutableTest {

    volatile ImmutableObject obj;

    public static void main(String[] args) throws InterruptedException {
        new ImmutableTest().execute();
    }

    private void execute() throws InterruptedException
    {
        obj = new ImmutableObject(0);
        ExecutorService exec = Executors.newFixedThreadPool(50);    
        for(int i = 0; i < 50; i++){
            exec.execute(new ImmutableRunnable(this));
        }
        Thread.sleep(5000);
        exec.shutdown();
        obj.print();
    }
}


public class ImmutableRunnable implements Runnable {
    ImmutableTest test;

    ImmutableRunnable(ImmutableTest immutableTest) {
        this.test = immutableTest;
    }

    public void run() {
        this.test.obj = new ImmutableObject(this.test.obj.getValue());
}

}

public final class ImmutableObject {

    private int n;

    public ImmutableObject(int newValue) {
        this.n = newValue;
        if(Math.random() > .5){
            try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
                e.printStackTrace();
        }
        }
    }

    public void print() {
        System.out.println(n);
    }

    public int getValue() {
        return n;
    }
}

在线程安全环境中,我预计结果为 50。但这种情况并非如此。如果从 ImmutableObject 构造函数中取消随机 sleep ,您将获得 50。

那么结论是什么? “如果构造函数足够快”,不可变对象(immutable对象)是线程安全的吗?或者(更有可能)我误解了什么?

抱歉,我没有正确解释我的疑问。这不是同步问题,我学习了如何同步方法和使用锁。这个问题涉及不可变对象(immutable对象)及其与多线程的关系。我到处都读到不可变对象(immutable对象)是线程安全的,因此它可以在线程之间无所畏惧地共享。但恕我直言,这根本不是真的!!! 那么你能给我一个不可变对象(immutable对象)在不同线程之间共享并且它的使用不需要同步的例子吗? 谢谢大家。

最佳答案

你误会了什么。

不可变对象(immutable对象)让您可以安全地共享对象并读取任何方法/字段,无需使用锁

在这种情况下,您依赖于 mutable obj 引用以某种方式进行同步 - 事实并非如此。

不变性只是一个无法修改的对象。修改状态后,您需要执行一些同步以确保实际发生您想要的。例如,整个“通过读取 obj 设置 obj”调用需要是互斥的,并且以串行方式发生。

关于用于多线程系统的 Java 不可变对象(immutable对象)。我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12632428/

相关文章:

Java ReentrantReadWriteLocks - 在读锁中如何安全地获取写锁?

带有 fork 的 Java 并行进程

c# - 如何实现线程安全列表?

java - Switch 语句导致 java :240 (might not have been initialized)

java - 无效选择器异常 : invalid selector: Compound class names not permitted

Python 使用 subprocess.Popen 关闭所有线程或进程

C (linux) - 模拟/跳过 scanf 输入

python - 我可以将多线程应用于 python 中的计算密集型任务吗?

java.sql.SQLException : No suitable driver found for jdbc:mysql://localhost/WORLD

java - 使用 Java Streams 将 double 映射汇总为聚合的 BigDecimal