- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
所以我有两个 AtomicBoolean,我需要检查它们。类似的东西:
if (atomicBoolean1.get() == true && atomicBoolean2.get() == false) {
// ...
}
但两者之间存在竞争条件 :(
有没有办法将两个原子 boolean 检查组合成一个而不使用同步(即同步块(synchronized block))?
最佳答案
好吧,我可以想到几种方法,但这取决于您需要的功能。
一种方法是“作弊”并使用 AtomicMarkableReference<Boolean> :
final AtomicMarkableReference<Boolean> twoBooleans = (
new AtomicMarkableReference<Boolean>(true, false)
);
void somewhere() {
boolean b0;
boolean[] b1 = new boolean[1];
b0 = twoBooleans.get(b1);
b0 = false;
b1[0] = true;
twoBooleans.set(b0, b1);
}
但这有点痛苦,只会给你两个值。
那么您可以将 AtomicInteger 与 bit flags 一起使用:
static final int FLAG0 = 1;
static final int FLAG1 = 1 << 1;
final AtomicInteger intFlags = new AtomicInteger(FLAG0);
void somewhere() {
int flags = intFlags.get();
int both = FLAG0 | FLAG1;
if((flags & both) == FLAG0) { // if FLAG0 has a 1 and FLAG1 has a 0
something();
}
flags &= ~FLAG0; // set FLAG0 to 0 (false)
flags |= FLAG1; // set FLAG1 to 1 (true)
intFlags.set(flags);
}
虽然有点痛苦,但它会给你 32 个值。如果你真的想要的话,你可以围绕它创建一个包装类。例如:
public class AtomicBooleanArray {
private final AtomicInteger intFlags = new AtomicInteger();
public void get(boolean[] arr) {
int flags = intFlags.get();
int f = 1;
for(int i = 0; i < 32; i++) {
arr[i] = (flags & f) != 0;
f <<= 1;
}
}
public void set(boolean[] arr) {
int flags = 0;
int f = 1;
for(int i = 0; i < 32; i++) {
if(arr[i]) {
flags |= f;
}
f <<= 1;
}
intFlags.set(flags);
}
public boolean get(int index) {
return (intFlags.get() & (1 << index)) != 0;
}
public void set(int index, boolean b) {
int f = 1 << index;
int current, updated;
do {
current = intFlags.get();
updated = b ? (current | f) : (current & ~f);
} while(!intFlags.compareAndSet(current, updated));
}
}
这还不错。也许在 get 中复制数组时执行了一组,但重点是您可以获取或以原子方式设置所有 32 个。 (比较和设置 do-while 循环非常丑陋,但它是原子类本身如何处理 getAndAdd 之类的东西。)
AtomicReference 在这里似乎不切实际。它允许原子获取和设置,但一旦你掌握了内部对象,你就不再以原子方式更新。您每次都必须创建一个全新的对象。
final AtomicReference<boolean[]> booleanRefs = (
new AtomicReference<boolean[]>(new boolean[] { true, true })
);
void somewhere() {
boolean[] refs = booleanRefs.get();
refs[0] = false; // not atomic!!
boolean[] copy = booleanRefs.get().clone(); // pretty safe
copy[0] = false;
booleanRefs.set(copy);
}
如果您想以原子方式对数据执行临时操作(获取 -> 更改 -> 设置,无干扰),您必须使用锁或同步。就我个人而言,我会使用锁或同步,因为通常情况下,整个更新就是您想要保留的内容。
不要这样做!
这可以(可能)用 sun.misc.Unsafe
来完成。这是一个使用 Unsafe 写入易变长牛仔风格的两半的类。
public class UnsafeBooleanPair {
private static final Unsafe UNSAFE;
private static final long[] OFFS = new long[2];
private static final long[] MASKS = new long[] {
-1L >>> 32L, -1L << 32L
};
static {
try {
UNSAFE = getTheUnsafe();
Field pair = UnsafeBooleanPair.class.getDeclaredField("pair");
OFFS[0] = UNSAFE.objectFieldOffset(pair);
OFFS[1] = OFFS[0] + 4L;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
private volatile long pair;
public void set(int ind, boolean val) {
UNSAFE.putIntVolatile(this, OFFS[ind], val ? 1 : 0);
}
public boolean get(int ind) {
return (pair & MASKS[ind]) != 0L;
}
public boolean[] get(boolean[] vals) {
long p = pair;
vals[0] = (p & MASKS[0]) != 0L;
vals[1] = (p & MASKS[1]) != 0L;
return vals;
}
private static Unsafe getTheUnsafe()
throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe)theUnsafe.get(null);
}
}
重要的是,Javadoc in the Open JDK source对于 fieldOffset
表示 不 对偏移量进行算术运算。然而,用它做算术似乎确实有效,因为我没有得到垃圾。
这对整个单词进行了一次 volatile 读取,但也(可能)对其中任何一半进行了 volatile 写入。 putByteVolatile
可用于将 long 拆分为 8 个段。
我不建议任何人使用它(不要使用它!),但它作为一个奇怪的东西有点有趣。
关于java - 如何在没有同步块(synchronized block)(即低成本锁)的情况下在一个安全操作中原子地检查 Java 中的两个 AtomicBooleans?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21925546/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!