Java同步线程

Java同步线程,java,multithreading,java.util.concurrent,Java,Multithreading,Java.util.concurrent,不确定此D类线程是否正确。是否存在竞争条件,i在被访问时是否应该在同步块中?如果D是一个外部类,而A实例被传递给了D构造函数,该怎么办 class A { int i; void f() { i++; D d = new D(); d.start(); } class D extends Thread { public void run() { int g = i;

不确定此D类线程是否正确。是否存在竞争条件,
i
在被访问时是否应该在同步块中?如果D是一个外部类,而A实例被传递给了D构造函数,该怎么办

class A
{
    int i;
    void f() {
        i++;
        D d = new D();
        d.start();
    }
    class D extends Thread {
        public void run() {
            int g = i;
        }
    }
}
有比赛条件吗

如果您在访问共享变量(
i
)时没有正确的同步,可能会从多个线程调用
f

但是请注意,启动线程会创建“发生在之前”关系


因此
g
将等于线程启动前
i
的值(即调用
d.start()
i
的值),或者如果同时另一个线程修改了
i
,则任何后续值(不保证实际看到这些修改).

只要只调用
f
一次,这是安全的。在变异数据的线程a和从线程a开始的线程B之间存在“先发生后发生”关系(HB关系位于
thread.start
)。由于在
D
启动后没有人对数据进行变异,因此这是安全的

一些破坏线程安全性的方法:

  • 再次变异
    i
    ,包括再次调用
    foo
  • D
    或调用
    foo的线程以外的线程读取
    i
您不能再次变异
i
,即使是从调用
foo
的线程,原因是该变异会发生在
d.start()
之后,因此对第二次变异没有HB优势

您无法从任何任意线程读取
i
的原因是该线程没有定义良好的
i++
变异视图


它可以得到比这更微妙的一点,但在较高的级别上,你就可以了。

如果从同一个线程调用
f()
,就不会有问题,因为
start()
保证
i
run()
中可见,并且
run()
不会更改
i
。否则,您需要
AtomicInteger
synchronized
。请注意,简单地
volatile i
是没有帮助的,一些
i++
可能会丢失。

完全不相关,因为其他人似乎已经介绍过了,但是扩展
线程
被认为是不好的做法。谷歌开发者总是在android示例代码中这样做!这是我的建议。这样,你就不会发现自己意外地重写了一些东西,也不会背上很多你不需要的额外内存包袱。在启动线程之前增加
i
,并且没有线程修改
i