Java的内存模型基于强制执行规则的“先有先后”关系,但也允许在缓存失效方面优化虚拟机的实现。
例如,在以下情况下:
// thread A
private void method() {
//code before lock
synchronized (lockA) {
//code inside
}
}
// thread B
private void method2() {
//code before lock
synchronized (lockA) {
//code inside
}
}
// thread B
private void method3() {
//code before lock
synchronized (lockB) {
//code inside
}
}
Run Code Online (Sandbox Code Playgroud)
如果线程A调用method()而线程B试图在lockA内部获取method2(),则同步lockA将要求线程B在释放其锁之前,观察线程A对所有变量所做的所有更改,甚至包括之前在“代码”中更改的变量。锁定”部分。
另一方面,method3()使用另一个锁并且不强制发生关系之前的事件。这为优化创造了机会。
我的问题是虚拟机如何实现那些复杂的语义?是否在不需要缓存时避免完全刷新缓存?
它如何跟踪在哪个点哪个线程更改了哪个变量,从而仅从内存加载所需的缓存行?
multithreading jvm memory-model happens-before vm-implementation
我正在尝试一些C#代码的Java端口,我很惊讶地看到javac 1.8.0_60 getfield每次访问一个对象字段时都会发出操作码.
这是Java代码:
public class BigInteger
{
private int[] bits;
private int sign;
//...
public byte[] ToByteArray()
{
if (sign == 0)
{
return new byte[] { 0 };
}
byte highByte;
int nonZeroDwordIndex = 0;
int highDword;
if (bits == null)
{
highByte = (byte)((sign < 0) ? 0xff : 0x00);
highDword = sign;
}
else if (sign == -1)
{
highByte = (byte)0xff;
assert bits.length > 0;
assert bits[bits.length - 1] != 0;
while …Run Code Online (Sandbox Code Playgroud) 我正在阅读"了解JVM高级功能和最佳实践",其中包含一个代码段,用于解释java中的先发制人规则.我不明白.代码如下:
private int value = 0;
//executed by Thread A
public void setValue(int value){
this.value = value;
}
//executed by Thread B
public void getValue(){
return value;
}
Run Code Online (Sandbox Code Playgroud)
假设A线程B在代码中的线程之前启动.我可以理解,我们不知道getValue()线程B 返回的结果,因为它不是线程安全的.但是,这本书说,如果添加的同步关键字的功能setValue()和getValue(),那么就没有存在线程安全问题和方法getValue()将返回正确的值.这本书解释说,因为synchronized符合先前发生的规则.所以我在下面的代码中有两个问题.
public class VolatileDemo3 {
private volatile int value = 0;
public static void main(String[] args) {
VolatileDemo3 v = new VolatileDemo3();
Thread A = new Thread(v.new Test1());// Thread A
Thread B = new Thread(v.new Test2());//Thread B …Run Code Online (Sandbox Code Playgroud) 考虑请求 - 响应协议.
我们生成一个线程来执行一个select()循环,用于读取和写入已接受的非阻塞SocketChannel.这可能看起来像
while (!isStopped()) {
selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey selectedKey = selectedKeys.next();
selectedKeys.remove();
Context context = (Context) selectedKey.attachment();
if (selectedKey.isReadable()) {
context.readRequest();
} else /* if (selectedKey.isWritable()) */ {
context.writeResponse();
}
}
}
Run Code Online (Sandbox Code Playgroud)
where Context只是一个容器,用于相应的SocketChannel,一个缓冲区和逻辑来读入它并从中写入.在readRequest可能看起来像
public void readRequest() {
// read all content
socketChannel.read(requestBuffer);
// not interested anymore
selectionKey.interestOps(0);
executorService.submit(() -> {
// handle request with request buffer and prepare response
responseBuffer.put(/* some response …Run Code Online (Sandbox Code Playgroud) 我目前正在攻读并发编程考试并且不明白为什么这个程序的输出是43.为什么x = y + 1之前执行t.start()?我还应该解释在我使用的规则之前发生了什么.
如果我理解程序顺序规则(一个线程中的每个动作发生 - 在该程序顺序后面的那个线程中的每个动作之前)t.start()都必须在执行之前执行,x = y + 1以便线程t复制变量x1.
public class HappensBefore {
static int x = 0;
static int y = 42;
public static void main(String[] args) {
x = 1;
Thread t = new Thread() {
public void run() {
y = x;
System.out.println(y);
};
};
t.start();
x = y + 1;
}
Run Code Online (Sandbox Code Playgroud) java concurrency multithreading java-memory-model happens-before
-Thread 1-
y.store (20, memory_order_release);
x.store (10, memory_order_release);
-Thread 2-
if (x.load(memory_order_acquire) == 10) {
assert (y.load(memory_order_acquire) == 20);
y.store (10, memory_order_release)
}
-Thread 3-
if (y.load(memory_order_acquire) == 10) {
assert (x.load(memory_order_acquire) == 10);
}
Run Code Online (Sandbox Code Playgroud)
GCC Atomic Wiki的 “总体摘要”段落说?上面的代码assert(x.load(memory_order_acquire))可能会失败。但是我不明白为什么?
我的理解是?
// Thread 1
// do A
x.store(1, std::memory_order_release); // operation1
// Thread 2
// do B
x.store(2, std::memory_order_release); // operation2
// Thread 3
x.load(std::memory_order_acquire); // operation3
Run Code Online (Sandbox Code Playgroud)
我知道,如果线程3读取线程1写入的值,则释放和获取操作将与同步,并且的效果A对线程3可见。
但是,如果是这样的话:
x是1、21和3之间是否存在事前关系?
还是本质上,修改顺序有助于事前发生关系?
我对Java的发生和同步有一些分歧.
想象一下以下场景:
主线程
MyObject o = new MyObject(); // (0)
synchronized (sharedMonitor) {
// (1) add the object to a shared collection
}
// (2) spawn other threads
Run Code Online (Sandbox Code Playgroud)
其他主题
MyObject o;
synchronized (sharedMonitor) {
// (3) retrieve the previously added object
}
// (4) actions to modify the object
Run Code Online (Sandbox Code Playgroud)
请注意,实例变量MyObject既不是volatile,也不是final.MyObject不使用同步的方法.
我的理解是:
1 发生在 3 之前,因为在同一个监视器上有同步,而其他线程仅在2处生成,这在1之后执行.
4上的操作无法保证以后对主线程可见,除非所有线程都进一步同步,并且主线程在这些操作之后以某种方式同步.
问:是否可以保证0处的操作可见,之前发生,3上的并发访问,或者我必须将变量声明为volatile? …
我正在读以下的书
Java Concurrency in Practice http://www.informit.com/store/java-concurrency-in-practice-9780321349606
我对关于Happens-before关系的具体解释感到困惑.
它说,
操作按照之前发生的部分排序进行排序
"偏序"究竟是什么意思?
(书中有一个解释,但我不清楚)
我有以下代码
class VolatileCount {
volatile int count;
Object lock = new Object();
public void increment() {
synchronized (lock) {
count = count + 1;
}
System.out.print(" " + count);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我increment()从多个线程调用相同的对象,我会得到以下输出(可能在您的机器上有所不同)
2 3 2 5 4 8 8 6 11 13 10 9 15 14 12 20 19
Run Code Online (Sandbox Code Playgroud)
看看我认为发生的重复数字似乎被破坏了,因为考虑前三个数字(2 3 2),如果线程看到3,则发生增量,并且因为变量是易变的,所以它的值应该是3或更多但是在任何线程中都不能为2.
但是,打印线似乎已在这里重新排序,重新排序该行是否正确?我在这里错过了什么?我运行JDK 7(Eclipse)
happens-before ×10
java ×7
c++ ×2
c++11 ×2
concurrency ×2
jvm ×2
memory-model ×2
atomic ×1
javac ×1
jls ×1
nio ×1
sockets ×1
stdatomic ×1
synchronized ×1