Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java多线程:AtomicInteger的快速替代方案_Java_Concurrency_Java.util.concurrent_Concurrentmodification - Fatal编程技术网

Java多线程:AtomicInteger的快速替代方案

Java多线程:AtomicInteger的快速替代方案,java,concurrency,java.util.concurrent,concurrentmodification,Java,Concurrency,Java.util.concurrent,Concurrentmodification,我有一个(大约250000个)状态未知、正确或错误的三态电池 所有细胞开始时都是未知的。然后一组大约60个线程(在AMD ThreadRipper 64核CPU上)进行计算,并将这些变量从未知设置为真或假 一旦为单元格指定了值,它就永远不会更改 如果两个线程通过不同的策略独立地计算出单元格的值应该是什么,那么同一个值可能会被分配给一个单元格两次。线程是否在稍后看到单元格发生了“某种程度上”的更改并不重要。如果另一个线程决定将TRUE赋值给值未知的单元格,则它决不能看到中间值FALSE。反之亦然

我有一个(大约250000个)状态未知、正确或错误的三态电池

所有细胞开始时都是未知的。然后一组大约60个线程(在AMD ThreadRipper 64核CPU上)进行计算,并将这些变量从未知设置为真或假

一旦为单元格指定了值,它就永远不会更改

如果两个线程通过不同的策略独立地计算出单元格的值应该是什么,那么同一个值可能会被分配给一个单元格两次。线程是否在稍后看到单元格发生了“某种程度上”的更改并不重要。如果另一个线程决定将TRUE赋值给值未知的单元格,则它决不能看到中间值FALSE。反之亦然

线程越早看到单元格的变化,效果越好。在这些条件下,我也不关心写重新排序

我目前正在使用
AtomicInteger
实现一个单元格。分析表明,我在这门课上花费了大约30%的计算时间

我能做些什么来改善这种情况

另外,我这样做是为了创建一个非图解算器。

正如我们在德国所说的“Einen Tod muss mann-sterben”,因此无法实现某种锁定或同步

volatile无法满足您的要求。

考虑这种情况:

  • 您有一个状态未知的单元格
  • 2个线程尝试同时更改状态
  • 一个要将状态更改为TRUE,另一个要将状态更改为FALSE
  • 两者都可以检索(在读取时,更正)未知的易失性值
  • 读取该值后,两个线程都会被中断并稍后恢复
  • 然后他们都会更新它
  • 也许他们两个都不会赢,但他们都认为自己赢了
这种情况有点做作,但也有可能&就像你正在做的那样,很有可能。这就是墨菲定律

多个线程仅能从volatile读取正确的值是不够的,它们需要确保状态在更新的期间保持不变,这就是为什么无法绕过某种锁定的原因

还请注意,广泛使用的双重检查锁定算法(至少在Java中)是一种错误的反模式。它将失败。你可以在维基百科上读到

尝试下面的概念验证计划。
它使用synchronized来解决您的需求&它坚如磐石。
性能:90秒内访问10亿次,多线程

import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class TriState {

    private static final byte TRI_STATE_UNKNOWN =  0;
    private static final byte TRI_STATE_TRUE    =  1;
    private static final byte TRI_STATE_FALSE   =  2;

    private              byte value = TRI_STATE_UNKNOWN;

    public  synchronized boolean isUnknown() {
        return value == TRI_STATE_UNKNOWN;
    }

    public  synchronized boolean isTrue() {
        return value == TRI_STATE_TRUE;
    }

    public  synchronized boolean isFalse() {
        return value == TRI_STATE_FALSE;
    }

    public  synchronized boolean doIfKnown(final Runnable runnable) {

        if (value != TRI_STATE_UNKNOWN) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfUnknown(final Runnable runnable) {

        if (value == TRI_STATE_UNKNOWN) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfNotTrue(final Runnable runnable) {

        if (value != TRI_STATE_TRUE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfTrue(final Runnable runnable) {

        if (value == TRI_STATE_TRUE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfNotFalse(final Runnable runnable) {

        if (value != TRI_STATE_FALSE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfFalse(final Runnable runnable) {

        if (value == TRI_STATE_FALSE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean setTrue() {
        /*
         * ok to set True if its Unknown or already True...
         */
        if (value != TRI_STATE_FALSE) {
            value =  TRI_STATE_TRUE;

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean setFalse() {
        /*
         * ok to set False if its Unknown or already False ...
         */
        if (value != TRI_STATE_TRUE) {
            value =  TRI_STATE_FALSE;

            return   true;
        } else {
            return   false;
        }
    }

    private static final int        SIZE      = 250_000;
    private static final TriState[] TRI_STATE = IntStream.range(0, SIZE).mapToObj(move -> new TriState()).toArray(TriState[]::new);

    public static void main(final String[] args) throws Exception {

        final ExecutorService pool     = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        final SecureRandom    rng      = new SecureRandom();

        final Duration        duration = Duration.ofSeconds(90);
        final Instant         end      = Instant.now().plus(duration);
        /*
         * Following accessed TRI_STATE 1,061,946,535 times in 90 seconds on a midrange Office PC...
         */
        pool.submit(() -> {
            while (Instant.now().isBefore(end)) {
                Arrays.stream(TRI_STATE).forEach(triState -> {
                    if (rng.nextBoolean()) {
                        triState.setTrue();
                    } else {
                        triState.setFalse();
                    }
                });
            }
        });
        pool.shutdown();
        pool.awaitTermination(duration.getSeconds(), TimeUnit.SECONDS);
    }
}
下面是一个示例,用于强调volatile将失败的原因:

public  boolean setTrue() {
    /*
     * Read out Status & if already set, we lost...
     */
    if (status != UNKNOWN) {
        return false;
    }
    /*
     * Status is Unknown here & just BEFORE doing the following, another Thread reads out Status.
     */
    /**/       status     =  TRUE;  // Update volatile Status
    /*
     * Now we can detect if that Thread modifies Status between these 2 lines of code...
     */
    return     status     == TRUE;  // Is volatile Status still True?
    /*
     * Just AFTER doing the above, that Thread updates Status to False, thinking its Unknown.
     * 
     * So now both Threads think they won & you are up a certain creek without a paddle!
     */
}
正如我们在德国所说的“Einen Tod muss mann sterben”,因此无法绕过某种锁定或同步

volatile无法满足您的要求。

考虑这种情况:

  • 您有一个状态未知的单元格
  • 2个线程尝试同时更改状态
  • 一个要将状态更改为TRUE,另一个要将状态更改为FALSE
  • 两者都可以检索(在读取时,更正)未知的易失性值
  • 读取该值后,两个线程都会被中断并稍后恢复
  • 然后他们都会更新它
  • 也许他们两个都不会赢,但他们都认为自己赢了
这种情况有点做作,但也有可能&就像你正在做的那样,很有可能。这就是墨菲定律

多个线程仅能从volatile读取正确的值是不够的,它们需要确保状态在更新的期间保持不变,这就是为什么无法绕过某种锁定的原因

还请注意,广泛使用的双重检查锁定算法(至少在Java中)是一种错误的反模式。它将失败。你可以在维基百科上读到

尝试下面的概念验证计划。
它使用synchronized来解决您的需求&它坚如磐石。
性能:90秒内访问10亿次,多线程

import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class TriState {

    private static final byte TRI_STATE_UNKNOWN =  0;
    private static final byte TRI_STATE_TRUE    =  1;
    private static final byte TRI_STATE_FALSE   =  2;

    private              byte value = TRI_STATE_UNKNOWN;

    public  synchronized boolean isUnknown() {
        return value == TRI_STATE_UNKNOWN;
    }

    public  synchronized boolean isTrue() {
        return value == TRI_STATE_TRUE;
    }

    public  synchronized boolean isFalse() {
        return value == TRI_STATE_FALSE;
    }

    public  synchronized boolean doIfKnown(final Runnable runnable) {

        if (value != TRI_STATE_UNKNOWN) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfUnknown(final Runnable runnable) {

        if (value == TRI_STATE_UNKNOWN) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfNotTrue(final Runnable runnable) {

        if (value != TRI_STATE_TRUE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfTrue(final Runnable runnable) {

        if (value == TRI_STATE_TRUE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfNotFalse(final Runnable runnable) {

        if (value != TRI_STATE_FALSE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean doIfFalse(final Runnable runnable) {

        if (value == TRI_STATE_FALSE) {
            runnable.run();

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean setTrue() {
        /*
         * ok to set True if its Unknown or already True...
         */
        if (value != TRI_STATE_FALSE) {
            value =  TRI_STATE_TRUE;

            return   true;
        } else {
            return   false;
        }
    }

    public  synchronized boolean setFalse() {
        /*
         * ok to set False if its Unknown or already False ...
         */
        if (value != TRI_STATE_TRUE) {
            value =  TRI_STATE_FALSE;

            return   true;
        } else {
            return   false;
        }
    }

    private static final int        SIZE      = 250_000;
    private static final TriState[] TRI_STATE = IntStream.range(0, SIZE).mapToObj(move -> new TriState()).toArray(TriState[]::new);

    public static void main(final String[] args) throws Exception {

        final ExecutorService pool     = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        final SecureRandom    rng      = new SecureRandom();

        final Duration        duration = Duration.ofSeconds(90);
        final Instant         end      = Instant.now().plus(duration);
        /*
         * Following accessed TRI_STATE 1,061,946,535 times in 90 seconds on a midrange Office PC...
         */
        pool.submit(() -> {
            while (Instant.now().isBefore(end)) {
                Arrays.stream(TRI_STATE).forEach(triState -> {
                    if (rng.nextBoolean()) {
                        triState.setTrue();
                    } else {
                        triState.setFalse();
                    }
                });
            }
        });
        pool.shutdown();
        pool.awaitTermination(duration.getSeconds(), TimeUnit.SECONDS);
    }
}
下面是一个示例,用于强调volatile将失败的原因:

public  boolean setTrue() {
    /*
     * Read out Status & if already set, we lost...
     */
    if (status != UNKNOWN) {
        return false;
    }
    /*
     * Status is Unknown here & just BEFORE doing the following, another Thread reads out Status.
     */
    /**/       status     =  TRUE;  // Update volatile Status
    /*
     * Now we can detect if that Thread modifies Status between these 2 lines of code...
     */
    return     status     == TRUE;  // Is volatile Status still True?
    /*
     * Just AFTER doing the above, that Thread updates Status to False, thinking its Unknown.
     * 
     * So now both Threads think they won & you are up a certain creek without a paddle!
     */
}

您是否尝试过将
Booealn
s(包装类)与
volatile
结合使用?这样,就可以表示一个三元状态:
true
false
是它们相应的对应项,对象是
null
表示
未知的状态。即使是非易失性字段也会满足您的要求:您永远不会看到没有线程写入的值。您可能会看到一个旧值(在您的情况下,这意味着
未知
),但决不会看到错误的值。在某些情况下,非易失性字段可能是最快的(如果看到正确的值“太迟”的惩罚比易失性字段的额外成本低)。如果对该结构的读/写是限制因素,那么可能每个线程的纯本地副本形式的读缓存就是解决方案。写回线程安全主副本,偶尔重新读取本地副本。也许你可以根据线程拆分单元格?您如何访问您的手机?有一个顺序?出于好奇,您使用哪种原子整数方法来设置值?set*方法、lazySet、compareAndSet等之间的性能可能存在差异。您是否尝试将
Booealn
s(包装类)与
volatile
结合使用?这样,就可以表示一个三元状态:
true
false
是它们相应的对应项,对象是
null
表示
未知的状态。即使是非易失性字段也会满足您的要求:您永远不会看到没有线程写入的值。您可能会看到一个旧值(在您的情况下,这意味着
未知
),但决不会看到错误的值。在某些情况下,非易失性字段可能只是