2013-05-08 151 views
3

不确定此D类线程是否正确。是否存在竞态条件,i应该在访问时处于同步块中?如果D是外部类,并且A实例被传递给了D构造函数呢?Java同步线程

class A 
{ 
    int i; 
    void f() { 
     i++; 
     D d = new D(); 
     d.start(); 
    } 
    class D extends Thread { 
     public void run() { 
      int g = i; 
     } 
    } 
} 
+2

完全无关,正如其他人似乎已经涉及到的,但延长'线程'被认为是不好的做法。 – pickypg 2013-05-08 06:13:37

+0

谷歌开发人员一直在android示例代码中执行此操作! – 2013-05-08 06:14:32

+3

下面是[更好的方法](http://stackoverflow.com/questions/1921514/how-to-run-a-runnable-thread-in-android)。这样,你不会发现自己意外地压倒性的东西,也不会带着你不需要的额外记忆包袱。 – pickypg 2013-05-08 06:19:15

回答

1

只要您只调用f一次,这是安全的。在数据变异的线程A和从线程A开始的线程B(HB关系在Thread.start)之间有一个发生在前的关系。由于D启动后没有人变更数据,因此这是安全的。

一些打破线程安全的方法:再次

  • 发生变异i,包括再次调用foo
  • 从比D其他线程或调用foo

一读i你不能再次改变i的原因是,即使是从调用foo的线程,也是这个变种会有hav e发生在d.start()之后,因此对于第二次突变没有HB边缘。

你不能从任意线程读取i的原因是,这个线程不会有一个明确的了i++突变的看法。

它可以比这更微妙,但在高层次,你去。

1

有一个竞争条件?

可能如果从一个以上的线程调用f像您没有适当同步地访问共享变量(i)。

但请注意,启动线程会创建一个发生之前的关系

所以g将等于i值线程启动权之前(即当d.start()被称为i值),或者如果i任何后续值已被在此期间另一个线程修改(不保证这种修改实际上是可见的)。

1

如果f()会从一个被调用,并在同一个线程不会有问题,因为start()保证irun()run()可见不改变i。否则,您需要AtomicInteger或​​。请注意,只需volatile i不会帮助,一些i++可能会丢失。