今天我实验室的敏感操作完全错了.电子显微镜上的执行器越过它的边界,在一系列事件之后,我损失了1200万美元的设备.我已将故障模块中的40K以上线路缩小到:
import java.util.*;
class A {
static Point currentPos = new Point(1,2);
static class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
new Thread() {
void f(Point p) {
synchronized(this) {}
if (p.x+1 != p.y) {
System.out.println(p.x+" "+p.y);
System.exit(1);
}
}
@Override
public void run() {
while (currentPos == null);
while (true)
f(currentPos);
}
}.start();
while (true)
currentPos = new Point(currentPos.x+1, currentPos.y+1);
} …Run Code Online (Sandbox Code Playgroud) 我的老师在一个关于线程的上层Java课上说了一些我不确定的东西.
他表示以下代码不一定会更新ready变量.根据他的说法,两个线程不一定共享静态变量,特别是在每个线程(主线程对ReaderThread)在其自己的处理器上运行并因此不共享相同的寄存器/缓存/等和一个CPU的情况下不会更新另一个.
从本质上讲,他说有可能ready在主线程中更新,但不在主线程中更新ReaderThread,因此ReaderThread将无限循环.
他还声称该程序可以打印0或42.我知道如何42打印,但不是0.他提到当number变量设置为默认值时会出现这种情况.
我想也许并不能保证在线程之间更新静态变量,但这对我来说非常奇怪.制作readyvolatile会纠正这个问题吗?
他展示了这段代码:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试在非最终字段的对象初始化不足的情况下重现内存可见性问题(JLS 17.5 Final Field Semantics,FinalFieldExample类示例).它声明"但是,fy不是最终的;因此,reader()方法不能保证看到它的值4"
我试过这段代码:
public class ReorderingTest2 {
public static void main(String[] args) {
for (int i = 0; i < 2500; i++) {
new Thread(new Reader(i)).start();
new Thread(new Writer(i)).start();
}
}
static class Reader implements Runnable {
private String name;
Reader(int i) {
this.name = "reader" + i;
}
@Override
public void run() {
//System.out.println(name + " started");
while (true) {
FinalFieldExample.reader(name);
}
}
}
static class Writer implements Runnable {
private String name; …Run Code Online (Sandbox Code Playgroud) java multithreading constructor processor-architecture memory-visibility
以下是经典Concurency in Practice:
当线程A写入volatile变量并且随后线程B读取相同的变量时,在写入volatile变量之前A可见的所有变量的值在读取volatile变量后变为B可见.
我不确定我是否真的能理解这句话.例如,在这种情况下所有变量的含义是什么?这是否意味着使用volatile也会对非易失性变量的使用产生副作用?
在我看来,这句话有一些我无法理解的微妙含义.
有帮助吗?
假设我有一个带有集合的并发映射值:
Map<Integer, List<Integer> map = new ConcurrentHashMap<>();
map.putIfAbsent(8, new ArrayList<>());
Run Code Online (Sandbox Code Playgroud)
我更新了如下值:
map.computeIfPresent(8, (i, c) -> {
c.add(5);
return c;
});
Run Code Online (Sandbox Code Playgroud)
我知道computeIfPresent整个方法调用是以原子方式执行的.但是,考虑到这个映射是由多个线程同时访问的,我有点担心对底层集合所做的修改的数据可见性.在这种情况下,调用后将在列表中看到值5map.get
我的问题是map.get如果在computeIfPresent方法调用中执行了更改,则在调用时将更改为列表在其他线程中可见.
请注意,如果我在执行更新操作之前参考列表,我知道列表的更改将不可见.如果我map.get在更新操作后引用列表(通过调用),我不确定列表的更改是否可见.
我不确定如何解释文档,但在我看来发生这种情况 - 在关系之前将保证在这种特定情况下对底层集合的更改的可见性
更正式地说,给定密钥的更新操作承担与该密钥的任何(非空)检索之前发生的关系,报告更新的值
我在一些OSS单元测试中经常看到这段代码,但它是否是线程安全的?while循环是否可以保证看到invoc的正确值?
如果不; nerd指向谁也知道哪个CPU架构可能会失败.
private int invoc = 0;
private synchronized void increment() {
invoc++;
}
public void isItThreadSafe() throws InterruptedException {
for (int i = 0; i < TOTAL_THREADS; i++) {
new Thread(new Runnable() {
public void run() {
// do some stuff
increment();
}
}).start();
}
while (invoc != TOTAL_THREADS) {
Thread.sleep(250);
}
}
Run Code Online (Sandbox Code Playgroud) java multithreading synchronized thread-safety memory-visibility
关于内存可见性的小问题.
CodeSample1:
class CustomLock {
private boolean locked = false;
public boolean lock() {
if(!locked) {
locked = true;
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
此代码在多线程环境中容易出错,首先是因为"if-then-act"不是原子的,其次是因为潜在的内存可见性问题,例如threadA将字段设置为true,但是threadB是后来希望读取该字段的值可能看不到,仍然看到值false.
最简单的解决方案是使用synchronized关键字,如CodeSample2中所示.
CodeSample2:
class CustomLock {
private boolean locked = false;
public synchronized boolean lock() {
if(!locked) {
locked = true;
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
现在如果我希望使用原子变量,例如,AtomicBoolean(问题适用于所有原子变量),
CodeSample3:
public static class CustomLock {
private AtomicBoolean locked = new AtomicBoolean(false);
public boolean lock() {
return locked.compareAndSet(false, true);
}
}
Run Code Online (Sandbox Code Playgroud)
除了更好的性能考虑之外,我们可以看到现在我们使用AtomicBoolean 实现了与CodeSample1的"if-then-act"类似的逻辑.逻辑上代码的作用并不重要, …
我已经阅读了第16.3节"初始化安全性"的一些解释 JCIP但仍然不清楚.该部分指出
"此外,任何可以通过正确构造的对象的最终字段(例如最终数组的元素或最终字段引用的HashMap的内容)到达的变量也可以保证对其他线程可见."
所以,如果我有以下可变对象:
public final class Container{
private String name;
private int cupsWon;
private double netWorth;
public Container( String name, int cupsWon, double netWorth ){
this.name = name;
this.cupsWon = cupsWon;
this.netWorth = netWorth;
}
//NO Setters
//Getters
}
Run Code Online (Sandbox Code Playgroud)
然后,线程1按如下方式创建它并将c传递给Thread2.
final Container c = new Container("Ted Dibiasi", 10, 1000000);
Run Code Online (Sandbox Code Playgroud)
Thread2(不是同时,假设在1 ms之后),读取c的值,是否有可能看到Thread2
c.name=null or
c.cupswon=0 or worst of all,
c.netWorth=0.0?
Run Code Online (Sandbox Code Playgroud)
干杯
我注意到有关吸气鬼的课程有些困惑.我正在更新源代码,希望这将是明确的.谢谢大家一起来看看.
public final class Container{
private String name;
private int cupsWon; …Run Code Online (Sandbox Code Playgroud) 在编写一些java文章时,我试图在多线程环境中的非同步对象构造的情况下重现重新排序.构建重型对象时没有同步/挥发性/韵母和其他线程在构造函数调用后立即访问它的情况.这是我尝试的代码:
public class ReorderingTest {
static SomeObject<JPanel>[] sharedArray = new SomeObject[100];
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
String name = "watcher" + i;
new Thread(new Watcher(name)).start();
System.out.printf("watcher %s started!%n", name);
}
}
static class Watcher implements Runnable {
private String name;
Watcher(String name) {
this.name = name;
}
public void run() {
while (true) {
int randomIndex = (int) (Math.random() * sharedArray.length);
SomeObject<JPanel> item = sharedArray[randomIndex];
if (item …Run Code Online (Sandbox Code Playgroud) 语境
我正在用 C++编写一个线程安全的原型线程/协程库,并且我正在使用原子来使任务切换无锁。我希望它尽可能高效。我对原子和无锁编程有一个大致的了解,但我没有足够的专业知识来优化我的代码。我做了很多研究,但很难找到我的具体问题的答案:不同内存顺序下不同原子操作的传播延迟/可见性是多少?
当前假设
我读到对内存的更改是从其他线程传播的,它们可能会变得可见:
我不确定这种延迟的可见性和不一致的传播是仅适用于非原子读取,还是也适用于原子读取,这可能取决于使用的内存顺序。当我在 x86 机器上开发时,我无法在弱有序系统上测试行为。
无论操作类型和使用的内存顺序如何,所有原子读取都总是读取最新值吗?
我很确定所有读-修改-写(RMW) 操作总是读取任何线程写入的最新值,而不管使用的内存顺序如何。对于顺序一致的操作似乎也是如此,但前提是对变量的所有其他修改也是顺序一致的。据说两者都很慢,这对我的任务不利。如果不是所有原子读取都获得最新值,那么我将不得不使用 RMW 操作来读取原子变量的最新值,或者在 while 循环中使用原子读取,以我目前的理解。
写入的传播(忽略副作用)是否取决于内存顺序和使用的原子操作?
(仅当上一个问题的答案是并非所有原子读取总是读取最新值时,此问题才有意义。请仔细阅读,我在这里不询问副作用的可见性和传播。我只关心原子变量本身的值。)这意味着根据用于修改原子变量的操作,可以保证任何后续原子读取接收变量的最新值。因此,我必须在保证始终读取最新值的操作之间进行选择,或者使用宽松的原子读取,以及这种特殊的写入操作,以保证对其他原子操作的修改的即时可见性。
java ×9
concurrency ×6
atomicity ×1
c++ ×1
constructor ×1
propagation ×1
static ×1
stdatomic ×1
synchronized ×1
volatile ×1