Java多线程:AtomicInteger的快速替代方案
我有一个(大约250000个)状态未知、正确或错误的三态电池 所有细胞开始时都是未知的。然后一组大约60个线程(在AMD ThreadRipper 64核CPU上)进行计算,并将这些变量从未知设置为真或假 一旦为单元格指定了值,它就永远不会更改 如果两个线程通过不同的策略独立地计算出单元格的值应该是什么,那么同一个值可能会被分配给一个单元格两次。线程是否在稍后看到单元格发生了“某种程度上”的更改并不重要。如果另一个线程决定将TRUE赋值给值未知的单元格,则它决不能看到中间值FALSE。反之亦然 线程越早看到单元格的变化,效果越好。在这些条件下,我也不关心写重新排序 我目前正在使用Java多线程:AtomicInteger的快速替代方案,java,concurrency,java.util.concurrent,concurrentmodification,Java,Concurrency,Java.util.concurrent,Concurrentmodification,我有一个(大约250000个)状态未知、正确或错误的三态电池 所有细胞开始时都是未知的。然后一组大约60个线程(在AMD ThreadRipper 64核CPU上)进行计算,并将这些变量从未知设置为真或假 一旦为单元格指定了值,它就永远不会更改 如果两个线程通过不同的策略独立地计算出单元格的值应该是什么,那么同一个值可能会被分配给一个单元格两次。线程是否在稍后看到单元格发生了“某种程度上”的更改并不重要。如果另一个线程决定将TRUE赋值给值未知的单元格,则它决不能看到中间值FALSE。反之亦然
AtomicInteger
实现一个单元格。分析表明,我在这门课上花费了大约30%的计算时间
我能做些什么来改善这种情况
另外,我这样做是为了创建一个非图解算器。正如我们在德国所说的“Einen Tod muss mann-sterben”,因此无法实现某种锁定或同步
volatile无法满足您的要求。
考虑这种情况:
- 您有一个状态未知的单元格
- 2个线程尝试同时更改状态
- 一个要将状态更改为TRUE,另一个要将状态更改为FALSE
- 两者都可以检索(在读取时,更正)未知的易失性值
- 读取该值后,两个线程都会被中断并稍后恢复
- 然后他们都会更新它
- 也许他们两个都不会赢,但他们都认为自己赢了
它使用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
- 两者都可以检索(在读取时,更正)未知的易失性值
- 读取该值后,两个线程都会被中断并稍后恢复
- 然后他们都会更新它
- 也许他们两个都不会赢,但他们都认为自己赢了
它使用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
表示未知的状态。即使是非易失性字段也会满足您的要求:您永远不会看到没有线程写入的值。您可能会看到一个旧值(在您的情况下,这意味着未知
),但决不会看到错误的值。在某些情况下,非易失性字段可能只是