Question

Ceci vient de JLS 17.5 :

Le modèle d'utilisation des champs finaux est simple.Définissez les champs finaux d'un objet dans le constructeur de cet objet. N'écrivez pas de référence à l'objet construit dans un endroit où un autre thread peut le voir avant la fin du constructeur de l'objet. Si cela est suivi, alors lorsque l'objet est vu par un autre thread, ce thread verra toujours la version correctement construite des champs finaux de cet objet.Il verra également des versions de tout objet ou tableau référencé par les champs finaux qui sont au moins aussi à jour que les champs finaux.

La discussion dans JLS 17.5 inclut cet exemple de 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
        }
    }
}

J'ai essayé de réutiliser ce code pour reproduire la situation ci-dessus, et voici ce que j'ai :

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

Je peux tester comment final est lu correctement, mais comment puis-je le répliquer lorsqu'il n'est pas lu correctement (c'est-à-direquand il y a une référence à la bande de roulement avant que le constructeur ait fini ?)

Était-ce utile?

La solution

Qu'est-ce que tu cherches

Ce que vous essayez de tester s'appelle Ne publiez pas la référence "this" pendant la construction ou Risque de visibilité.Lisez les liens suivants dans l’ordre dans lequel ils sont fournis.

En lisant

  1. Théorie et pratique Java :Techniques de construction sûres
  2. FAQ JSR 133 (modèle de mémoire Java)
  3. Les garanties « à jour » pour les valeurs des champs finaux de Java s'étendent-elles aux références indirectes ?

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

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

Explication du résultat

Lorsque j'accède au champ final du constructeur de mon thread, à ce moment-là, le final champ x n'a pas été correctement initialisé, et c'est pourquoi nous obtenons 0. Whereas lorsque j'accède au même champ dans le run() puis à ce moment-là, le final champ x est initialisé à 3.Cela se produit à cause du escaping de la référence à l'objet de FinalField.Lis le 1er lien que j'ai partagé, il est beaucoup plus détaillé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top