相关疑难解决方法(0)

为什么这个Java程序会终止,尽管显然它不应该(并没有)?

今天我实验室的敏感操作完全错了.电子显微镜上的执行器越过它的边界,在一系列事件之后,我损失了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 concurrency java-memory-model memory-visibility

205
推荐指数
3
解决办法
5万
查看次数

为什么Java构造函数不能同步?

根据Java语言规范,构造函数不能被标记为同步,因为在创建它的线程完成之前,其他线程无法看到正在创建的对象.这看起来有点奇怪,因为在构造对象时我确实可以有另一个线程查看对象:

public class Test {
    public Test() {
       final Test me = this;
       new Thread() {
           @Override
           public void run() {
               // ... Reference 'me,' the object being constructed
           }
       }.start();
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这是一个非常人为的例子,但理论上似乎有人可以提出一个更现实的案例,标记构造函数同步将是合法的,以防止像这样的线程的比赛.

我的问题是:Java有没有理由不在构造函数上禁用synchronized修饰符?也许我上面的例子是有缺陷的,或者也许没有理由,这是一个任意的设计决定.在任何一种情况下,我都很好奇,很想知道答案.

java constructor language-design synchronized

63
推荐指数
5
解决办法
3万
查看次数

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

尽管没有代码明确泄漏,未初始化的对象泄露给另一个线程?

让我们看看这个简单的Java程序:

import java.util.*;

class A {
    static B b;
    static class B {
        int x;
        B(int x) {
            this.x = x;
        }
    }
    public static void main(String[] args) {
        new Thread() {
            void f(B q) {
                int x = q.x;
                if (x != 1) {
                    System.out.println(x);
                    System.exit(1);
                }
            }
            @Override
            public void run() {
                while (b == null);
                while (true) f(b);
            }
        }.start();
        for (int x = 0;;x++)
            b = new B(Math.max(x%2,1));
    }
}
Run Code Online (Sandbox Code Playgroud)

主线程

主线程创建的实例Bx设置为1,则该实例写入静态字段 …

java concurrency initialization memory-visibility

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