标签: java-memory-model

Java 并发 - 发布不可变对象(Java 并发实践)

在 Java Concurrency In Practice 中,作者表示

  1. 不可变对象可以通过任何机制发布
  2. 任何线程都可以安全地使用不可变对象,而无需额外的同步,即使不使用同步来发布它们。

是否意味着以下习语可以安全地发布不可变对象?

public static List<ImmutableObject> list = new ArrayList<ImmutableObject>();

// thread A invokes this method first
public static void methodA () {
    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}
Run Code Online (Sandbox Code Playgroud)

会有数据竞赛吗?(这意味着线程 B 可能无法看到线程 A 添加的列表中的不可变对象)

非常感谢。


更进一步,作者说如果Resource是不可变的,下面的代码是安全的。

@NotThreadSafe
public class UnsafeLazyInitialization {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null)
            resource = new Resource();  // unsafe publication …
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading java-memory-model

3
推荐指数
1
解决办法
1371
查看次数

java中的同步和代码重新排序

在某些链接中,给出了同步块内的代码重新排序是可能的,而其他一些站点则告诉这是不可能的。您能否举一个例子来描述使用同步时代码重新排序实际发生的情况?

java multithreading jvm synchronized java-memory-model

3
推荐指数
1
解决办法
1313
查看次数

在Java中使用volatile集合和数组

想象一下,我们有

volatile int publisher = 0;
volatile List<String> list = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
volatile String[] array = {"Buenos Aires", "Córdoba", "La Plata"};
Run Code Online (Sandbox Code Playgroud)

据我所理解.

列表和数组中的初始值正确发布,并且对所有读取线程都可见.

初始化后添加的所有值都不是安全发布的.

我们仍然可以安全地阅读和发布它们

//in Thread 1
list.add("Safe City");
array[2] = "Safe city";
publisher = 1;

//in Thread2

if(publisher == 1) {
String city = list.get(3);
city = array[2];
}
Run Code Online (Sandbox Code Playgroud)

我对吗?

java collections concurrency volatile java-memory-model

3
推荐指数
2
解决办法
4261
查看次数

Java 内存模型中线程发散动作和外部动作的示例

我目前正在学习 Java 内存模型,并且了解了不同类型的Actions。

其中有两个我不完全理解:

  • 外部行动和
  • 线程发散动作

请解释这两种操作类型并举例说明它们以及它们关于编译器重新排序和发生在关系之前的特殊属性。哦,本地调用也是外部操作吗?

我认为如果它们没有什么特别之处,它们就不会定义线程发散动作。那么是什么让它们与众不同,以至于需要将它们定义为一种特殊的动作呢?

java java-native-interface multithreading native java-memory-model

3
推荐指数
1
解决办法
356
查看次数

为什么没有波动?

我和同事讨论了这段代码:

public final class ShutdownHookRegistration {

/**
 * Global shutdown flag
 */
private static boolean isServerShutdown = false;

private ShutdownHookRegistration() {
    // empty
}

/**
 * Returns the current value of the global shutdown flag
 *
 * @return
 */
public static boolean isServerShutdown() {
    return isServerShutdown;
}

/**
 * Registration if shutdown hooks
 */
public static void registerShutdownHooks() {
    /**
     * 1. Shutdown hook to set the shutdown flag
     */
    Runtime.getRuntime().addShutdownHook(setGlobalShutdownFlag());
}

/**
 * Sets the global static is shutdown …
Run Code Online (Sandbox Code Playgroud)

java multithreading volatile static-variables java-memory-model

3
推荐指数
1
解决办法
88
查看次数

Java内存模型中的部分构造的对象

我在Internet上某处的文章中遇到了以下代码:

public class MyInt {

    private int x;

    public MyInt(int y) {
        this.x = y;
    }

    public int getValue() {
        return this.x;
    }
}
Run Code Online (Sandbox Code Playgroud)

文章指出

编译器(JIT,CPU等)不对构造器进行特殊处理,因此允许对构造器中的指令和构造器之后的指令进行重新排序。

另外,关于Java内存模型的这篇JSR-133文章指出:

保证只有在对象完全初始化之后才能看到对对象的引用的线程才能确保看到该对象的最终字段的正确初始化值。

上面提到的MyInt实例似乎是不可变的(除了未标记该类的情况final)并且是线程安全的,但文章指出并非如此。他们声明不能保证x读取时始终具有正确的值。

但是我认为

在创建对象时,只有创建对象的线程才可以访问它

和Java教程都显得很支持。

我的问题是:这是否意味着在当前的JMM中,由于指令重新排序,线程可以访问部分构造的对象?如果是的话,怎么办?这是否意味着Java教程中的陈述是不正确的?

java concurrency final java-memory-model

3
推荐指数
1
解决办法
302
查看次数

当您丢弃对 SoftReference 的引用时,它的清除仍会放在 ReferenceQueue 上吗?

我想了解垃圾收集器在什么情况下会通知您清除软引用。文档清楚地表明它在可能发生 OOM 时发生,但是如果您完全丢弃引用,GC 会出现并收集 SoftReference 可能会注意到不存在其他强/软引用并清除内部引用值。

ReferenceQueue<Object> cleared = new ReferenceQueue<>();
Object X = new Object();
SoftReference<Object> Xs = new SoftReference<>(X, cleared);

Thread.sleep(10);
X = null;
Xs = null;

System.GC();
Thread.sleep(100);
Reference ref;
while ((ref = cleared.poll()) != null) {
   System.err.println(ref);
}
Run Code Online (Sandbox Code Playgroud)

那么关于这个队列的规则记录在哪里?一定有比我问的更多的极端情况,所以也许这个问题必须扩大一点。

java garbage-collection soft-references java-memory-model

3
推荐指数
1
解决办法
99
查看次数

使用 volatile 字段安全发布对象

来自Java Concurrency In Practice一书:

要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。正确构造的对象可以通过以下方式安全地发布:

  • 从静态初始化器初始化对象引用;
  • 将对其的引用存储到 volatile 字段或 AtomicReference 中;
  • 将对其的引用存储到正确构造的对象的最终字段中;或者
  • 将对其的引用存储到由锁正确保护的字段中。

我的问题是:

为什么要点 3 有约束:“正确构造的对象”,而要点 2 没有?

以下代码是否安全地发布map实例?我认为代码符合要点 2 的条件。

public class SafePublish {

    volatile DummyMap map = new DummyMap();

    SafePublish() throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // Safe to use 'map'?
                System.out.println(SafePublish.this.map);
            }
        }).start();
        Thread.sleep(5000);
    }

    public static void main(String[] args) throws InterruptedException {
        SafePublish safePublishInstance = new SafePublish();
    }
 

public …
Run Code Online (Sandbox Code Playgroud)

java concurrency volatile java-memory-model safe-publication

3
推荐指数
1
解决办法
121
查看次数

Java 易失性内存排序及其在 x86-64 上的编译

考虑以下简单的 Java 应用程序:

public class Main {
    public int a;
    public volatile int b;

    public void thread1(){
        int b;
        a = 1;
        b = this.b;
    }

    public void thread2(){
        int a;
        b = 1;
        a = this.a;
    }

    public static void main(String[] args) throws Exception {
        Main m = new Main();
        while(true){
            m.a = 0;
            m.b = 0;
            Thread t1 = new Thread(() -> m.thread1());
            Thread t2 = new Thread(() -> m.thread2());
            t1.start();
            t2.start();
            t1.join();
            t2.join();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题: …

java x86-64 volatile java-memory-model memory-barriers

3
推荐指数
1
解决办法
277
查看次数

android中的最大BackStack大小

我是android开发的新手.我需要知道的最大内存大小的堆栈中的机器人
,我想知道有多少活动的Android应用程序可以被存储在堆栈中

谢谢

android java-memory-model back-stack

2
推荐指数
1
解决办法
1666
查看次数