Java同步线程
不确定此D类线程是否正确。是否存在竞争条件,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;
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
。