100%不可变,但仍然不是线程安全的

时间:2018-10-17 11:29:10

标签: java multithreading thread-safety immutability

我已经阅读了很多有关线程安全的知识。在我的多线程程序的某些部分,我更喜欢尝试不变性。得到不正确的结果后,我注意到我的不可变对象不是线程安全的,尽管它是100%不可变的。如果我错了,请纠正我。

public final class ImmutableGaugeV4 {
private final long max, current;

public ImmutableGaugeV4(final long max) {
    this(max, 0);
}

private ImmutableGaugeV4(final long max, final long current) {
    this.max = max;
    this.current = current;
}

public final ImmutableGaugeV4 increase(final long increament) {
    final long c = current;
    return new ImmutableGaugeV4(max, c + increament);
}

public final long getCurrent() {
    return current;
}

public final long getPerc() {
    return current * 100 / max;
}

@Override
public final String toString() {
    return "ImmutableGaugeV4 [max=" + max + ", current=" + current + "](" + getPerc() + "%)";
}
 }

aaaaa

public class T4 {
public static void main(String[] args) {
    new T4().x();
}

ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);

private void x() {
    for (int i = 0; i < 10; i++) {
        new Thread() {
            public void run() {
                for (int j = 0; j < 1000; j++) {
                    g3 = g3.increase(1);
                    System.out.println(g3);
                }
            }

        }.start();
    }
}
}

有时候我得到正确的结果,而且大多数时候我没有得到

ImmutableGaugeV4 [max=10000, current=9994](99%)
ImmutableGaugeV4 [max=10000, current=9995](99%)
ImmutableGaugeV4 [max=10000, current=9996](99%)
ImmutableGaugeV4 [max=10000, current=9997](99%)

这个不可变的对象怎么了?在不使用内部锁的情况下使其成为线程安全的缺少什么?

2 个答案:

答案 0 :(得分:1)

都不是

final long c = current;
return new ImmutableGaugeV4(max, c + increament);

g3 = g3.increase(1);

是线程安全的。这些复合动作不是原子的。

我建议阅读Brian Goetz的“实践中的Java并发性”:专门讨论复合动作和“发布和逃逸”问题的章节。

答案 1 :(得分:0)

您的问题是您没有对数字变量max和current使用线程安全操作。因此,即使已经更改了许多线程,许多线程也可以从中获得相同的值。

您可以添加同步块来处理对它们的读/写,但是最好的方法是使用线程安全类为您处理这些事情。

如果需要长值,则为AtomicLong。看看它的文档,它具有执行所需操作的方法。

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html

无论何时使用多线程,都应该使用线程安全的对象,例如Atomic系列,用于地图的ConcurrentHashMap等。

希望有帮助!