有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

不需要新变量声明的小函数的java可读性

我需要一些关于小方法的代码结构的建议。 下面是来自JavaAPI的一个方法。收藏。阶级

private static Random r;    
public static void shuffle(List<?> var0) {
    Random var1 = r;
    if (var1 == null) {
       r = var1 = new Random();
    }
    shuffle(var0, var1);
}

代码可以重写为

private static Random r;    
public static void shuffle(List<?> var0) {
    if (r == null) {
       r = new Random();
    }
    shuffle(var0, r);
}

我想知道第二种方法是否有我没有的副作用。 在什么情况下,一方会选择一种特定的方式而不是另一方


共 (1) 个答案

  1. # 1 楼答案

    原始源代码如下所示

    public static void shuffle(List<?> list) {
        Random rnd = r;
        if (rnd == null)
            r = rnd = new Random(); // harmless race.
        shuffle(list, rnd);
    }
    

    以及设计背后的要点提示。该代码使用共享字段r,并且不是线程安全的,但其设计方式使其后果是“无害的”

    显然,您不应该以这种方式设计软件。对于某些他们认为性能很重要的软件,这就留给了专家们。(实际上,shuffle方法可能不属于这一类)

    那么你的选择呢

    private static Random r;    
    public static void shuffle(List<?> var0) {
        if (r == null) {
           r = new Random();
        }
        shuffle(var0, r);
    }
    

    丢失线程安全性的后果不会是无害的。测试r == null和后续调用shuffle(var0, r)具有对r的不同读取,虽然应该只有从初始null到初始化的Random实例的转换,但是在没有使用线程安全机制的情况下,读取和写入可能会被认为是无序的,因此当发生并发写入时,r == null可以计算为false,而随后的shuffle(var0, r)读取null

    这并不意味着这个变体是错误的。如果您将您的方法或包含的类记录为线程不安全,并且在被不同的线程使用时需要外部同步,那么不会有任何错误

    Collections类的shuffle方法将r的值读入局部变量,以确保rnd == null测试和shuffle(list, rnd)调用将使用相同的值。由于这可能会读取对另一个线程创建的Random实例的引用,因此它依赖于Random实例本身是线程安全的这一事实,否则,racy读取可能会显示不一致的对象状态

    读操作仍然可能会遗漏先前由另一个线程写入的值,或者在读取null和随后写入对新创建的Random实例的引用之间发生另一个线程的写入。因此,多个线程可能会在这里构造和使用不同的Random实例,这被认为是“无害”的结果

    如前所述,您不应复制此模式。相反,您可以选择线程安全或无线程安全,并将您的代码记录下来