编程知识 cdmana.com

Principe de mise en œuvre ultime du mécanisme de concurrence Java sous - jacent

C'est ma participation11Le défi du mois de juin13Oh, mon Dieu.,Voir les détails de l'événement:2021Un dernier défi

Un.、finalUtilisation de la Fondation

1.1、Classe de modification

Quand une classe est définie commefinalHeure,C'est - à - dire que cette classe ne peut pas avoir de sous - classes,finalToutes les méthodes de la classe sont implicitementfinal,Impossible de les écraser,Donc, dansfinalIl n'y a aucun sens à ajouter des mots - clés à une méthode dans une classe.

finalComment les classes de type s'étendent?
Les deux relations les plus importantes dans les modèles de conception,L'un est l'héritage/Réalisation;L'autre est la relation combinatoire.Donc quand vous rencontrez quelqu'un qui ne peut pas hériter(finalClasse modifiée),Envisager une combinaison.
Copier le Code

1.2、Méthode de modification
  • privateLa méthode est implicitefinal
  • finalLa méthode peut être surchargée


private final:Tous dans la classeprivateLes méthodes sont implicitement désignées commefinalDe,Parce qu'il n'y a pas d'accèsprivateMéthodes, Donc on ne peut pas l'écraser ,C'est exact.private Méthode ajoutée finalMots clés, Ce n'est pas bon de faire ça .

finalLa méthode peut être surchargée:ParentfinalLa méthode ne peut pas être dépassée par une sous - classe,AlorsfinalLa méthode peut être surchargée?C'est bon.


1.3、Paramètres de modification

Java Permet d'indiquer un paramètre comme final, Cela signifie que l'objet auquel la référence du paramètre se réfère ne peut pas être modifié dans la méthode , Cette fonctionnalité est principalement utilisée pour transmettre des données à des classes internes anonymes .


1.4、Modifier la variable

Tous lesfinal Les champs modifiés sont - ils tous des constantes de temps de compilation ?

public class Test {
    //Constante de temps de compilation
    final int i = 1;
    final static int J = 1;
    final int[] a = {1,2,3,4};
    // Constante de temps non compilée 
    Random r = new Random();
    final int k = r.nextInt();

    public static void main(String[] args) {

    }
}
Copier le Code

k La valeur de est déterminée par un objet aléatoire , Donc ce n'est pas tout final Les champs modifiés sont tous des constantes de temps de compilation ,C'est juste...k La valeur de ne peut pas être modifiée après initialisation .

1.5、static final

L'un est à la foisstaticEncorefinal Les champs de ne prennent qu'une partie de l'espace de stockage qui ne peut pas être modifiée , Il doit être assigné au moment de la définition , Sinon, le compilateur ne passera pas .

import java.util.Random;
public class Test {
    static Random r = new Random();
    final int k = r.nextInt(10);
    static final int k2 = r.nextInt(10); 
    public static void main(String[] args) {
        Test t1 = new Test();
        System.out.println("k="+t1.k+" k2="+t1.k2);
        Test t2 = new Test();
        System.out.println("k="+t2.k+" k2="+t2.k2);
    }
}
Copier le Code

Résultats de l'exécution :

k=2 k2=7
k=8 k2=7
Copier le Code

static Le champ modifié par le mot - clé n'appartient pas à un objet , C'est ce qui appartient à cette classe ,Peut également être interprété commestatic final Le champ modifié ne prend qu'une partie de la mémoire , Une fois initialisé, il ne sera pas modifié .

2.、finalRéorganisation des champs

2.1、finalLe champ est de type de base
public class FinalDemo {
    private int a;  //Domaine normal
    private final int b; //finalDomaine
    private static FinalDemo finalDemo;

    public FinalDemo() {
        a = 1; // 1.  Écrivez le champ normal 
        b = 2; // 2. Écris.finalDomaine
    }

    public static void writer() {
        finalDemo = new FinalDemo();
    }

    public static void reader() {
        FinalDemo demo = finalDemo; // 3. Lire la référence de l'objet 
        int a = demo.a;    //4. Lire le champ normal 
        int b = demo.b;    //5.LirefinalDomaine
    }
}
Copier le Code

Supposons que le threadAEn courswriter()Méthodes,ThreadBMise en œuvrereader()Méthodes.

Écris.finalRéorganisation des champs:

Écris.final Le réarrangement des champs interdit les paires finalRéécriture des champs en dehors du constructeur, La mise en œuvre de cette règle comporte principalement deux aspects :
1、JMMInterdire au compilateur de mettrefinalRéécriture des champs en dehors du constructeur;
2、Le compilateur serafinalAprès l'écriture du domaine,ConstructeurreturnAvant,Insérer unstorestoreBarrière. Cette barrière peut empêcher le processeur de finalRéécriture des champs en dehors du constructeur.

AnalysewriterMéthodes:
1、Construit unFinalDemoObjet;
2、 Assigner cet objet à la variable membre finalDemo.

image.png

image.png


Parce quea、bAucune dépendance à l'égard des données entre,Domaine normal(Variables générales)a Peut être réorganisé en dehors du constructeur ,ThreadB Il est possible de lire des variables ordinaires a Valeur avant initialisation (0), Cela pourrait causer des erreurs .EtfinalVariables de domaineb, Selon la réorganisation , Il va interdire finalVariables modifiéesb Réorganiser en dehors du constructeur ,Et doncb Capable d'attribuer correctement les valeurs ,ThreadB Pour pouvoir lire final Valeur après initialisation de la variable .

Donc,,Écris.final La réorganisation des champs garantit : Avant que la référence de l'objet ne soit visible pour n'importe quel thread ,Objetfinal Le domaine a été correctement initialisé , Et le domaine commun n'a pas cette garantie .

LirefinalRéorganisation des champs:

Lirefinal La réorganisation des champs est :Dans un fil, Première lecture référence de l'objet et première lecture cet objet contient finalDomaine,JMM Le Réarrangement de ces deux opérations est interdit , Le processeur va lire finalInsérer unLoadLoadBarrière,En fait,, Lire la référence de l'objet et final Le domaine a une dépendance indirecte , En général, le processeur ne réorganise pas ces deux opérations . Mais il y a des processeurs qui vont réorganiser .Donc,, Cette interdiction de réarrangement est définie pour ces processeurs .

read() La méthode comprend principalement trois opérations :
1、 Première lecture des variables de référence finalDemo;
2、 Première lecture des variables de référence finalDemo Domaine normal de a;
3、 Première lecture des variables de référence finalDemoDefinalDomaineb;

image.png

image.png


Un thread apparaît lorsque le champ normal de l'objet de lecture est réorganisé avant la référence de l'objet de lecture B Les variables de domaine normales de l'objet sont lues avant que la référence de l'objet ne soit lue , Il s'agit d'un mauvais fonctionnement .Etfinal L'opération de lecture du champ est limitée à la lecture final Une référence à cet objet a déjà été lue avant la variable de domaine , Pour éviter cette situation .

Lirefinal La réorganisation des champs garantit :Lire un objetfinal Avant le domaine , Lisez d'abord celui qui contient ceci finalRéférence de l'objet du domaine.


2.2、finalLe champ est le type de référence


C'est exact.final Écrire le champ membre de l'objet modifié :

Pour le type de données de référence ,final L'écriture de domaine ajoute une telle contrainte à la réorganisation du compilateur et du processeur :Dans le constructeur, pour unfinal Écrire le champ membre de l'objet modifié , Et ensuite assigner une référence à cet objet construit à une variable de référence en dehors du constructeur , Ces deux opérations ne peuvent pas être réorganisées .

public class FinalReferenceDemo {
    final int[] arrays;
    private FinalReferenceDemo finalReferenceDemo;

    public FinalReferenceDemo() {
        arrays = new int[1];  //1
        arrays[0] = 1;        //2
    }

    public void writerOne() {
        finalReferenceDemo = new FinalReferenceDemo(); //3
    }

    public void writerTwo() {
        arrays[0] = 2;  //4
    }

    public void reader() {
        if (finalReferenceDemo != null) {  //5
            int temp = finalReferenceDemo.arrays[0];  //6
        }
    }
}
Copier le Code

Si le filAMise en œuvrewriterOneMéthodes, Filetage après exécution BMise en œuvrewriterTwoMéthodes,Et le filCMise en œuvrereaderMéthodes\

image.png

image.png


Parce quefinal L'écriture d'un champ interdit le réarrangement en dehors de la méthode de construction ,Donc,1Et3 Impossible de réorganiser .A cause d'unfinal L'écriture d'un domaine membre d'un objet de référence pour un domaine ne peut pas être réorganisée avec l'attribution ultérieure de cet objet construit à une variable de référence ,Donc,2Et3Impossible de réorganiser

C'est exact.final Opération de lecture du champ membre pour l'objet modifié

JMM Peut s'assurer que le fil C Au moins vous pouvez voir le fil d'écriture AC'est exact.finalÉcrire le champ membre de l'objet référencé, Je peux voir arrays[0] = 1, Et écrire des fils B Écrire à un élément de tableau peut être vu et peut ne pas être vu .JMM Les fils ne sont pas garantis B Write thread for CVisible,ThreadB Et les filsC Il y a concurrence entre les données , Le résultat est imprévisible . Si visible , La serrure peut être utilisée ou volatile.

版权声明
本文为[Java de cuisine Tao]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/11/20211125174154987O.html

Scroll to Top