线程中的最终字段语义 [英] Final Fields Semantics in Threads

查看:171
本文介绍了线程中的最终字段语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是来自JLS 17.5:

This is from JLS 17.5:


最终字段的使用模型很简单。在该对象的构造函数中设置
对象的最终字段。 在对象的构造函数
完成之前,不要在另一个线程可以看到的地方构建对
的对象的引用。
如果遵循这个,那么当对象时另一个线程,
看到该线程将始终看到该对象的最终
字段的正确构造版本。它还会看到最终
字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的。

The usage model for final fields is a simple one. Set the final fields for an object in that object's constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

JLS 17.5中的讨论包括以下示例代码:

The discussion in JLS 17.5 includes this sample code:

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
        }
    }
}

I尝试重用此代码来复制上面的情况,这就是我所拥有的:

I tried reusing this code to replicate the situation above, and here is what I have:

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();
    }
}

我可以测试最终如何正确读取,但是如何我可以在没有正确读取时复制(即在构造函数完成之前有对胎面的引用?)

I can test how final gets read correctly, but how can I replicate when it is not read correctly (i.e. when there is a reference to the tread before the constructor is finished?)

推荐答案

您在寻找什么



您要测试的内容称为在施工期间不要发布this参考可见性危害。请按照提供的顺序阅读以下链接。

What you are looking for

What you are trying to test is called Don't publish the "this" reference during construction or Visibility Hazard. Read the following links in the order they are provided.


  1. < a href =http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html =nofollow noreferrer> Java理论与实践:安全施工技术

  2. JSR 133( Java内存模型)常见问题解答

  3. 对Java的最终字段值的'最新'保证是否延伸到间接引用?

  1. Java theory and practice: Safe construction techniques
  2. JSR 133 (Java Memory Model) FAQ
  3. Do the ‘up to date’ guarantees for values of Java's final fields extend to indirect references?



示例代码



Sample Code

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();
        }
    }
}

输出

value of x = 0
value of x = 0
value of x = 0
.
.
.
value of x = 0
value of x = 0
value of x = 0



输出的说明



当我访问我的线程的构造函数中的最后一个字段时,那时 final 字段 x 未正确初始化,这就是我们获得 0 的原因。 然后 当我访问 run()然后到那时 final 字段 x 初始化为 3 。这是因为对 FinalField 的对象的引用的转义。阅读我分享的 1st 链接,它是更加详细。

Explanation of the output

When I access the final field in the constructor of my thread then at that time the final field x was not properly initialized, and that's why we are getting 0. Whereas when I access the same field in the run() then by that time the final field x is initialized to 3. This is happening because of the escaping of the reference to the object of FinalField. Read the 1st link I have shared, it is much more detailed.

这篇关于线程中的最终字段语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆