标签: safe-publication

Java多线程和安全发布

在阅读" 实践中的Java并发 "和" 实践中的OSGI "后,我发现了一个非常有趣的特定主题; 安全出版.以下内容来自JCIP:

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

  • 静态初始化程序初始化对象引用.
  • 将对它的引用存储到volatile字段中.
  • 将对它的引用存储到最终字段中.
  • 将对它的引用存储到由(同步)锁定正确保护的字段中.

我的第一个问题:有多少java开发人员知道这个(问题)?有多少真实世界的Java应用程序真正遵循这个,这真的是一个真正的问题吗?我有一种感觉,99%的已实现的JVM不是那种"邪恶",即一个线程不能保证(事实上它实际上(几乎)"不可能")看到陈旧数据只是因为引用不遵循上面的"安全出版成语".

java multithreading safe-publication

39
推荐指数
2
解决办法
8759
查看次数

Java中的并发对象创建

我正在读Brian Goetz的一本书"实践中的Java并发".第3.5和3.5.1段包含我无法理解的陈述.

请考虑以下代码:

public class Holder {
  private int value;
    public Holder(int value) { 
    this.value = value;
  }

  public void assertValue() {
    if (value != value) throw new AssertionError("Magic");
  }
}

class HolderContainer {
  // Unsafe publication
  public Holder holder;

  public void init() {
    holder = new Holder(42);  
  }
}
Run Code Online (Sandbox Code Playgroud)

作者说:

  1. 在Java中,Object构造函数首先在子类构造函数运行之前将默认值写入所有字段.
  2. 因此,可以将字段默认值视为过时值.
  3. 线程可能在第一次读取字段时看到陈旧值,然后在下次读取更新的值,这就是assertN可以抛出AssertionError的原因.

因此,根据文本,有些不幸的时机可能值= 0; 在下一刻,值= 42.

我同意第1点,Object构造函数首先使用默认值填充字段.但我不明白第2和第3点.

让我们更新作者代码并考虑以下示例:

public class Holder {
  int value;

  public Holder(int value) {
    //Sleep to prevent constructor to finish too early
    try { …
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading object safe-publication

11
推荐指数
1
解决办法
195
查看次数

安全发布本地最终参考文献

我知道你可以安全地发布一个非线程安全的对象,方法是将一个final或一个volatile字段的引用写入,稍后将被其他一个线程读取,前提是在发布时,创建该对象的线程会丢弃对它的引用,以便它不能再干扰或不安全地观察对象在另一个线程中的使用.

但在这个例子中,没有显式final字段,只有final局部变量. 如果调用者丢弃其引用unsafe,这是安全的出版物吗?

void publish(final Unsafe unsafe) {
    mExecutor.execute(new Runnable() {
        public void run() {
            // do something with unsafe
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现了一些Q&As,就像这个一样,暗示final局部变量被隐式"复制"到匿名类中.这是否意味着上面的例子等同于此?

void publish(final Unsafe unsafe) {
    mExecutor.execute(new Runnable() {
        final Unsafe mUnsafe = unsafe;
        public void run() {
            // do something with mUnsafe
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑以澄清:

Unsafe 可能是什么,但说它是这样的:

public class Unsafe {
    public int x;
}
Run Code Online (Sandbox Code Playgroud)

并且mExecutor是满足合同的任何东西Executor.

java multithreading safe-publication

9
推荐指数
1
解决办法
332
查看次数

线程是否可以先通过安全发布获取对象,然后不安全地发布它?

阅读此答案后,我想到了这个问题

代码示例:

class Obj1 {
  int f1 = 0;
}

volatile Obj1 v1;
Obj1 v2;

Thread 1            | Thread 2 | Thread 3
-------------------------------------------------
var o = new Obj1(); |          |
o.f1 = 1;           |          |
v1 = o;             |          |
                    | v2 = v1; |
                    |          | var r1 = v2.f1;

Is (r1 == 0) possible?
Run Code Online (Sandbox Code Playgroud)

这里的对象o

  • 首次安全发布:从Thread 1Thread 2通过volatile字段v1
  • 然后不安全地发布:从Thread 2Thread 3 …

java multithreading java-memory-model jls safe-publication

8
推荐指数
2
解决办法
373
查看次数

易失性保证安全发布可变对象?

通过阅读Java Concurrency in Practice

我可以看到:

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

  • 从静态初始化程序初始化对象引用
  • 将对它的引用存储到volatile字段或AtomicReference中
  • 将对它的引用存储到正确构造的对象的最终字段中
  • 将对它的引用存储到由锁正确保护的字段中.

但是,我对第二个成语感到困惑.因为volatile只能保证引用对另一个线程可见,它没有引用的对象构造的同步.那么如何保证可变对象被正确构造,构造该对象的线程被另一个线程中断了?

java concurrency multithreading volatile safe-publication

7
推荐指数
2
解决办法
515
查看次数

如何安全发布StringBuffer?

由于StringBuffer是线程安全的,因此可以安全地发布.考虑StringBuffer(来源)的公共构造函数:

public StringBuffer() {
    super(16);
}
Run Code Online (Sandbox Code Playgroud)

在哪里super(16)指定这个:

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}
Run Code Online (Sandbox Code Playgroud)

其中值声明为

char[] value;
Run Code Online (Sandbox Code Playgroud)

问题:如何StringBuffer安全发布?

我有以下课程:

public class Holder{
     public final StringBuffer sb = new StringBuffer();
}
Run Code Online (Sandbox Code Playgroud)

它可以被视为安全出版物吗?我想,它不可能.

final保证我们会看到参考的新值sb.但写入sb内部状态AbstractStringBuilder(int capacity)并不是同步的.因此,有没有happens-before这反过来又意味着,从读命令value调用发生时,sb.append(2);并写入value在构造函数是活泼的.

你能帮忙理解这个吗?也许我错过了什么......

java multithreading safe-publication

5
推荐指数
1
解决办法
82
查看次数

从多个线程对 Kotlin var 进行线程安全访问

考虑以下 Kotlin 代码:

import kotlin.concurrent.thread

fun main() {
    println("Press <Enter> to terminate.")

    var interrupted = false

    val worker = thread {
        while (!interrupted) {
            println("Working...")
            Thread.sleep(1000L)
        }
    }

    System.`in`.read()

    println("Terminating...")
    interrupted = true

    worker.join()

    println("Terminated.")
}
Run Code Online (Sandbox Code Playgroud)

以及使用协程重写的相同示例:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    println("Press <Enter> to terminate.")

    var interrupted = false

    val worker = launch(Dispatchers.IO) {
        while (!interrupted) {
            println("Working...")
            delay(1000L)
        }
    }

    System.`in`.read()

    println("Terminating...")
    interrupted = true

    worker.join()

    println("Terminated.")
}
Run Code Online (Sandbox Code Playgroud)

这两个示例在大多数情况下都可以工作,但都被破坏了,因为在字节码级别,boolean …

concurrency multithreading kotlin safe-publication kotlin-coroutines

4
推荐指数
1
解决办法
7029
查看次数

使用 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
查看次数