Isa*_*aac 6 java multithreading final thread-safety jls
这是来自JLS 17.5:
最终字段的使用模型很简单.在该对象的构造函数中设置对象的最终字段.在对象的构造函数完成之前,不要在另一个线程可以看到的位置写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.
JLS 17.5中的讨论包括以下示例代码:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试重用这段代码来复制上面的情况,这就是我所拥有的:
public class FinalFieldThread extends Thread {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadB.start();
threadA.start();
//threadB.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
System.out.println("ThreadA");
FinalFieldExample.writer();
}
}
class ThreadB extends Thread {
@Override
public void run() {
System.out.println("ThreadB");
FinalFieldExample.reader();
}
}
Run Code Online (Sandbox Code Playgroud)
我可以测试final是如何正确读取的,但是当它没有被正确读取时我怎么能复制(即在构造函数完成之前有一个对胎面的引用?)
您要测试的内容称为"在施工期间不显示"此"参考"或" 可见性危险".请按照提供的顺序阅读以下链接.
class FinalField
{
final int x;
int y;
public FinalField()
{
Thread t = new Thread(new TestThread(this));
t.start();
y = 4;
x = 3;
}
}
class TestThread implements Runnable
{
FinalField f;
TestThread(FinalField f)
{
if(f.x != 3)
System.out.println("value of x = " + f.x);
this.f = f;
}
public void run()
{
if(f.x != 3)
System.out.println("value of x = " + f.x);
}
}
public class Test
{
public static void main(String[] args)
{
for(int i=0; i<100; i++)
{
new FinalField();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Output
value of x = 0
value of x = 0
value of x = 0
.
.
.
value of x = 0
value of x = 0
value of x = 0
Run Code Online (Sandbox Code Playgroud)
当我访问我的线程的构造函数中的最后一个字段时,那时该final字段x没有正确初始化,这就是我们得到的原因0.Whereas当我在run()那时访问相同的字段时,该final字段x被初始化为3.这是因为对escaping对象的引用FinalField.阅读我分享的第一个链接,它更加详细.