考虑下面的Java示例.请注意,两个类成员变量都没有声明为volatile.如果我正在理解内存模型并且"之前发生"规则正确,那么Java实现可以优化该run()方法,以便它永远运行,即使另一个线程调用该stopNow()方法.这可能发生,因为run()方法中没有任何内容强制线程stop多次读取值.那是对的吗?如果没有,为什么不呢?
class Example implements Runnable {
boolean stop = false;
int value = 0;
public void stopNow() {
stop = true;
}
public int getValue() {
return value;
}
@Override
public void run() {
// Loop until stop is set to true.
while (!stop) {
++value;
}
return;
}
}
Run Code Online (Sandbox Code Playgroud) 从Java 5开始,volatile关键字具有释放/获取语义,以使副作用对其他线程可见(包括对非易失性变量的赋值!).拿这两个变量,例如:
int i;
volatile int v;
Run Code Online (Sandbox Code Playgroud)
请注意,这i是一个常规的非易失性变量.想象一下线程1执行以下语句:
i = 42;
v = 0;
Run Code Online (Sandbox Code Playgroud)
在稍后的某个时间点,线程2执行以下语句:
int some_local_variable = v;
print(i);
Run Code Online (Sandbox Code Playgroud)
根据Java存储器模型,v线程1中的写入以及线程2中的读取v确保线程2看到i在线程1中执行的写入,因此打印值42.
我的问题是:volatile在C#中是否有相同的发布/获取语义?
假设我创建了一个对象,并运行了父类的一个构造函数.使用此构造函数,在幕后创建父对象的新对象?
如果没有,private父类的字段存储在哪里?实际上,您可以调用父对象的任何方法(有或没有super),该对象操作调用对象不可见的私有字段.
如果有人最熟悉Java内存模型,那么非常欢迎他或她的回答!
关于JLS ch17 线程和锁,它说"如果一个动作发生在另一个之前,那么第一个动作在第二个之前可见并且在第二个之前被命令"; 我想知道:
(1)说"之前订购"的真正含义是什么?因为即使action_a发生在action_b之前,action_a也可以在action_b之后的某些实现中执行,对吧?
(2)如果action_a发生在action_b之前,是否意味着action_a绝不能看到action_b?或者action_a可能会看到或看不到action_b?
(3)如果action_a没有发生 - 在action_b之前,而action_b没有发生 - 在action_a之前,是否意味着action_a可能会看到或看不到action_b?
(4)之前没有任何循环发生,对吧?
任何答案将不胜感激:)
JLS 的内存模型部分(17.4)以合理的细节描述了volatile非volatile读写的语义,以及与某些其他结构(如监视器进入和退出)的交互.
然而,这并不能完全解释的语义compareAndSwap,也不lazySet在java.util.concurrent.atomic中*类.因为compareAndSet,你有javadoc包中的blurb :
compareAndSet and all other read-and-update operations such as getAndIncrement
have the memory effects of both reading and writing volatile variables.
Run Code Online (Sandbox Code Playgroud)
lazySet 提供了一些更难以理解的模糊:
lazySet has the memory effects of writing (assigning) a volatile variable
except that it permits reorderings with subsequent (but not previous)
memory actions that do not themselves impose reordering constraints with
ordinary non-volatile writes. Among other usage contexts, lazySet may …Run Code Online (Sandbox Code Playgroud) 在JSR-133中,有两个例子可能是状态正确同步的程序.
第一个例子如图6所示,其中:
x == y == 0
Run Code Online (Sandbox Code Playgroud)
然后,线程1通过以下方式修改状态:
r1 = x;
if (r1 != 0)
y = 1;
Run Code Online (Sandbox Code Playgroud)
和线程2通过以下方式修改状态:
r2 = y;
if (r2 != 0)
x = 1;
Run Code Online (Sandbox Code Playgroud)
作者声明该程序已正确同步,但是,此程序的执行会导致r1 == r2 == 1.后一个价值怎么可能呢?
此外,图7表示初始状态:
x == y == 0
Run Code Online (Sandbox Code Playgroud)
用线程1修改:
r1 = x;
y = r1;
Run Code Online (Sandbox Code Playgroud)
和线程2执行:
r2 = y;
x = r2;
Run Code Online (Sandbox Code Playgroud)
怎么会导致这种情况r1 == r2 == 42?
我们有一个在Docker中运行的Java应用程序.它有时会被oom-killer杀死,即使所有JVM统计数据看起来都不错.我们有许多其他应用程序没有这样的问题.
我们的设置:
JVM报告的各种内存统计信息(我们每隔10秒获取一次数据):
来自容器的日志(可能稍微不正常,因为我们使用相同的时间戳获取所有内容):
java invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0
java cpuset=47cfa4d013add110d949e164c3714a148a0cd746bd53bb4bafab139bc59c1149 mems_allowed=0
CPU: 5 PID: 12963 Comm: java Tainted: G ------------ T 3.10.0-514.2.2.el7.x86_64 #1
Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 04/14/2014
0000000000000000 0000000000000000 0000000000000046 ffffffff811842b6
ffff88010c1baf10 000000001764470e ffff88020c033cc0 ffffffff816861cc
ffff88020c033d50 ffffffff81681177 ffff880809654980 0000000000000001
Call Trace:
[<ffffffff816861cc>] dump_stack+0x19/0x1b
[<ffffffff81681177>] dump_header+0x8e/0x225
[<ffffffff8118476e>] oom_kill_process+0x24e/0x3c0
[<ffffffff810937ee>] ? has_capability_noaudit+0x1e/0x30
[<ffffffff811842b6>] ? find_lock_task_mm+0x56/0xc0
[<ffffffff811f3131>] mem_cgroup_oom_synchronize+0x551/0x580
[<ffffffff811f2580>] ? mem_cgroup_charge_common+0xc0/0xc0
[<ffffffff81184ff4>] pagefault_out_of_memory+0x14/0x90
[<ffffffff8167ef67>] mm_fault_error+0x68/0x12b
[<ffffffff81691ed5>] __do_page_fault+0x395/0x450
[<ffffffff81691fc5>] do_page_fault+0x35/0x90 …Run Code Online (Sandbox Code Playgroud) 我有一些不是线程安全的类:
class ThreadUnsafeClass {
long i;
long incrementAndGet() { return ++i; }
}
Run Code Online (Sandbox Code Playgroud)
(我在long这里使用了a 作为字段,但我们应该将其字段视为一些线程不安全的类型).
我现在有一个看起来像这样的课程
class Foo {
final ThreadUnsafeClass c;
Foo(ThreadUnsafeClass c) {
this.c = c;
}
}
Run Code Online (Sandbox Code Playgroud)
也就是说,线程不安全类是它的最后一个字段.现在我要这样做:
public class JavaMM {
public static void main(String[] args) {
final ForkJoinTask<ThreadUnsafeClass> work = ForkJoinTask.adapt(() -> {
ThreadUnsafeClass t = new ThreadUnsafeClass();
t.incrementAndGet();
return new FC(t);
});
assert (work.fork().join().c.i == 1);
}
}
Run Code Online (Sandbox Code Playgroud)
也就是说,从thread T(main),我调用了一些工作T'(fork-join-pool),它创建并改变了我的不安全类的实例,然后返回包含在a中的结果Foo.请注意,我的线程不安全类的所有变异都发生在一个线程上T'.
问题1:我是否保证thread-unsafe-class实例的结束状态安全地移植到?的 …
java parallel-processing fork-join java-memory-model java-stream
我试图理解java unsafe中的两个方法:
public native short getShortVolatile(Object var1, long var2);
Run Code Online (Sandbox Code Playgroud)
VS
public native short getShort(Object var1, long var2);
Run Code Online (Sandbox Code Playgroud)
这有什么真正的区别?这里的挥发性真正起作用了什么?我在这里找到了API doc:http://www.docjar.com/docs/api/sun/misc/Unsafe.html#getShortVolatile( Object,%20long)
但它并没有真正解释两种功能之间的区别.
我的理解是,对于不稳定的,它只对我们写作时很重要.对我来说,我们调用putShortVolatile然后进行读取应该是有意义的,我们可以简单地调用,getShort()因为volatile写入已经保证新值已经刷新到主存储器中.
如果有任何问题,请帮我纠正.谢谢!
考虑这个(完全人为的)Java代码:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
a[0] = 100;
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
System.out.println(a[0]);
Run Code Online (Sandbox Code Playgroud)
此代码是否保证输出"106"?
似乎不存在,除非有一个先发生过的关系建立起来parallelStream(),通过它我们可以肯定地知道a[0]lambda 中的第一次访问将看到100而不是零(根据我对Java内存模型的理解).
但Collection.parallelStream()没有记录建立这种关系......
可以询问完成parallelStream()方法调用的相同问题.
所以我错过了一些东西,或者为了正确性,上述代码需要看起来像这样:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
synchronized (a) {
a[0] = 100;
}
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
synchronized (a) …Run Code Online (Sandbox Code Playgroud) java ×9
java-stream ×2
volatile ×2
bytebuffer ×1
c# ×1
concurrency ×1
docker ×1
fork-join ×1
jls ×1
jvm ×1
jvm-hotspot ×1
linux ×1
memory ×1
memory-model ×1
unsafe ×1