


L'intervieweur vous demande?: Savez-vous ce qu'est un problème ABA??
Jul 26, 2023 pm 03:09 PMLa civette échange contre le prince
Avant de commencer à expliquer le problème, jetons un coup d'?il à une courte histoire :
Après la mort de l'impératrice Zhenzong de la dynastie des Song du Nord, ses deux concubines bien-aimées à l'époque, Concubine Liu et Concubine Li. Elles sont toutes enceintes. Il est évident que celui qui donnera naissance à un fils pourra devenir le palais principal. La concubine Liu était jalouse depuis longtemps, craignant que la concubine Li ne donne naissance à un fils et ne devienne reine, alors elle a élaboré un plan avec Guo Huai, le directeur du palais, Dutang, et avec la coopération de la sage-femme Youshi, Concubine Li. est mort du coma pendant l'accouchement. De fa?on inattendue, la fourrure d'un chat civette a été enlevée, elle était sanglante et brillante et a emporté le prince nouveau-né. La concubine Liu a ordonné à la servante du palais Kou Zhu d'étrangler le prince à mort. Kou Zhu n'a pas pu le supporter et a secrètement remis le prince à l'eunuque Chen Lin. Chen Lin a mis le prince dans une valise et l'a envoyé aux huit rois sages. pour l'élever. De plus, Zhenzong a vu la civette écorchée et a pensé que la concubine Li avait donné naissance à un monstre, alors il l'a rétrogradée au palais froid. Bient?t, la concubine Liu était en travail et a donné naissance à un fils, qui a été nommé prince et a également été nommée reine. De fa?on inattendue, six ans plus tard, le fils de la reine Liu est mort de maladie. Zhenzong n'avait plus d'héritiers, il adopta donc le fils de son frère a?né Baxian Wang (en fait le prince qui avait été remplacé cette année-là) comme fils adoptif et l'établit comme prince héritier.
On peut voir dans cette histoire que le prince a été remplacé par un chat civette à sa naissance, et est finalement revenu pour devenir le prince par un étrange concours de circonstances. Bien que le résultat soit le même, le processus est tortueux et le prince a vraiment un mauvais sort.
Pourquoi raconter cette histoire ? En fait, cela a beaucoup à voir avec la question que nous allons introduire aujourd’hui. Avec le même résultat, je ne sais pas combien d’opérations ont eu lieu au milieu, alors peut-on penser que cela n’a pas changé ? Dans différents scénarios commerciaux, nous devons examiner attentivement cette question.
Description du problème ABA
Dans un scénario multithreadCAS
會(huì)出現(xiàn)ABA
, voici une science simple sur le problème ABA. Par exemple, il y a deux threads qui effectuent des opérations CAS sur la même valeur (la valeur initiale est. A) en même temps. Ceci Les trois fils sont les suivants :
Thread 1, la valeur attendue est A, la valeur à mettre à jour est B Thread 2, la valeur attendue est A, la valeur à mettre à jour est B
Thread 1 obtient la tranche de temps CPU d'abord, tandis que le thread 2 obtient la tranche de temps CPU en premier pour d'autres raisons. La raison est bloquée. La valeur du thread 1 est comparée à la valeur attendue de A. Elle s'avère égale, puis la valeur est mise à jour vers B. Ensuite. à ce moment, le thread 3 appara?t, la valeur attendue est B, la valeur à mettre à jour est A et la valeur du thread 3 est la même que la valeur attendue. Comparez la valeur B et si elle s'avère égale, mettez à jour. la valeur à A. à ce moment, le thread 2 récupère du blocage et obtient la tranche de temps CPU. à ce moment, la valeur du thread 2 est comparée à la valeur attendue A. Si elle s'avère égale, la valeur est mise à jour. à B. , bien que le thread 2 ait également terminé l'opération, le thread 2 ne sait pas que la valeur a suivi le processus de modification de A->B->A.
Donnez-moi un exemple précis
Xiao Ming a retiré 50 yuans du distributeur automatique de billets. En raison d'un problème avec le distributeur automatique de billets, il y a eu deux fils de discussion et le solde est passé de 100 à 50 en même temps. heure :
-
Thread 1 (cash machine) : obtenez la valeur actuelle 100, prévoyez une mise à jour à 50 ; Thread 2 (cash machine) : obtenez la valeur actuelle 100, attendez-vous à une mise à jour à 50 ; Le fil 1 a été exécuté avec succès, le fil 2 est bloqué pour une raison quelconque ; - à ce moment-là, quelqu'un remet 50 à Xiao Ming ;
- Thread 3 (par défaut)?: obtient la valeur actuelle de 50 et s'attend à ce qu'elle soit être mis à jour à 100. à ce moment, le thread 3 est exécuté avec succès et le solde devient 100
- Le thread 2 récupère du bloc et obtient 100. Après comparaison, il continue de mettre à jour le solde à 50.
- Vous pouvez voir à ce stade que le solde réel devrait être
100(100-50+50)
,但是實(shí)際上變?yōu)榱?code style='font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);'>50(100-50+50-50)
Pour résoudre le problème ABA, vous pouvez ajouter un numéro de version. Chaque fois que la valeur de l'emplacement mémoire V est modifiée, le numéro de version est augmenté de 1
.Exemple de code
Résolution des problèmes ABA via AtomicStampedReference
AtomicStampedReference conserve la valeur de l'objet et le numéro de version en interne. Lors de la création d'un objet AtomicStampedReference, vous devez transmettre la valeur initiale et numéro de version initiale?;
Lorsque AtomicStampedReference définit la valeur de l'objet, la valeur de l'objet et le tampon d'état doivent correspondre à la valeur attendue pour que l'écriture réussisse.
private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100,1); public static void main(String[] args) { //第一個(gè)線程 new Thread(() -> { System.out.println("t1拿到的初始版本號(hào):" + atomicStampedReference.getStamp()); //睡眠1秒,是為了讓t2線程也拿到同樣的初始版本號(hào) try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } atomicStampedReference.compareAndSet(100, 101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1); atomicStampedReference.compareAndSet(101, 100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1); },"t1").start(); // 第二個(gè)線程 new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println("t2拿到的初始版本號(hào):" + stamp); //睡眠3秒,是為了讓t1線程完成ABA操作 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最新版本號(hào):" + atomicStampedReference.getStamp()); System.out.println(atomicStampedReference.compareAndSet(100, 2019,stamp,atomicStampedReference.getStamp() + 1) + "\t當(dāng)前值:" + atomicStampedReference.getReference()); },"t2").start(); }
1. Valeur initiale 100, numéro de version initiale 1
2. Les threads t1 et t2 obtiennent le même numéro de version initial
3. Le thread t1 termine l'opération ABA et le numéro de version est augmenté à 3
4. .Thread t2 L'opération CAS est terminée. Le dernier numéro de version est devenu 3, ce qui n'est pas égal au numéro de version 1 obtenu par le thread t2 auparavant. Résolvez le problème ABA via AtomicMarkableReference
, La seule différence entre AtomicMarkableReference est qu'il n'utilise plus int pour identifier la référence, mais utilise une variable booléenne pour indiquer si la variable de référence a été modifiée.
t1拿到的初始版本號(hào):1 t2拿到的初始版本號(hào):1 最新版本號(hào):3 false 當(dāng)前值:100
3. Opération, et le numéro de version a été modifié vrai 2 Les fils de discussion t1 et t2 ont obtenu le même numéro de version initial et n'ont pas été modifiés faux
4. Le fil t2 a terminé l'opération CAS, ce qui n'est pas égal au numéro de version faux obtenu par le fil t2 auparavant. L'opération a échoué
Exécution. résultat : AtomicStampedReference
可以給引用加上版本號(hào),追蹤引用的整個(gè)變化過程,如:A -> B -> C -> D -> A,通過AtomicStampedReference,我們可以知道,引用變量中途被更改了3次。但是,有時(shí)候,我們并不關(guān)心引用變量更改了幾次,只是單純的關(guān)心是否更改過,所以就有了AtomicMarkableReference
t1版本號(hào)是否被更改:false t2版本號(hào)是否被更改:false 是否更改過:true false 當(dāng)前值:100
多說幾句
以上是本期關(guān)于CAS領(lǐng)域的一個(gè)經(jīng)典ABA問題的解析,不知道你在實(shí)際的工作中有沒有遇到過,但是在面試中這塊是并發(fā)知識(shí)考查的重點(diǎn)。如果你還沒接觸過此類的問題,我的建議是你自己將上面的代碼運(yùn)行一下,結(jié)合理論去理解一下ABA問題所帶來的問題以及如何解決他,這對(duì)你日后的開發(fā)工作也是有莫大的幫助的!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Vérification de la sécurité PHP via CAS (CentralAuthenticationService) Avec le développement rapide d'Internet, la gestion des droits des utilisateurs et la vérification de l'identité deviennent de plus en plus importantes. Lors du développement d’applications Web, il est crucial de protéger les données des utilisateurs et d’empêcher tout accès non autorisé. Afin d'atteindre cet objectif, nous pouvons utiliser CAS (CentralAuthenticationService) pour la vérification de la sécurité PHP. CAS

1. Expliquez que lorsque plusieurs threads effectuent des opérations CAS sur une ressource en même temps, un seul thread réussit, mais il ne bloquera pas les autres threads, et les autres threads recevront uniquement un signal indiquant que l'opération a échoué. On peut voir que CAS est en réalité un verrou optimiste. 2. En suivant le code AtomInteger, nous pouvons constater que sum.misc.Unsafe est finalement appelé. Regardez le nom Unsafe, c'est une classe non sécurisée qui exploite exactement les bonnes failles dans les règles de classe et de visibilité de Java. Par souci de rapidité, Unsafe fait quelques compromis sur les normes de sécurité de Java. publicfinalnativebooleancompareAndSwapInt(Objet

Explication CAS?: CAS (comparer et échanger), comparer et échanger. Un mécanisme qui peut résoudre la perte de performances causée par l'utilisation de verrous dans des situations parallèles multithreads. L'opération CAS contient trois opérandes?: l'emplacement mémoire (V), la valeur d'origine attendue (A) et la nouvelle valeur (B). Si la valeur d'un emplacement mémoire correspond à la valeur d'origine attendue, le processeur met automatiquement à jour l'emplacement avec la nouvelle valeur. Sinon, le processeur ne fait rien. Un thread obtient la valeur num de la mémoire principale et opère sur num Lors de l'écriture de la valeur, le thread comparera la première valeur num obtenue avec la valeur num dans la mémoire principale. Si elles sont égales, la valeur modifiée sera num. S'ils ne sont pas égaux, la comparaison sera bouclée jusqu'à ce qu'elle réussisse. Fabriqué par CAS

Qu'est-ce que CASCAS, c'est CompareAndSwap, c'est-à-dire comparer et échanger. Pourquoi CAS n'utilise-t-il pas de verrous mais assure-t-il néanmoins une manipulation s?re des données dans des conditions concurrentes ? Le nom montre en fait le principe de CAS de manière très intuitive. Le processus spécifique de modification des données est le suivant : Lorsque vous utilisez CAS pour exploiter des données, la valeur originale des données. et la valeur à modifier sont Transmettez-la à la méthode pour comparer si la valeur actuelle de la variable cible est la même que la valeur d'origine transmise. Si elles sont identiques, cela signifie que la variable cible n'a pas été modifiée par d'autres threads. Modifiez simplement la valeur de la variable cible directement. Si la valeur de la variable cible est différente de la valeur d'origine, alors prouvez que la variable cible a été modifiée par d'autres threads. à partir du processus ci-dessus, nous pouvons voir que CAS a en fait échoué. garantit une modification s?re des données, mais il existe des cas où la modification échoue.

Concurrence verrouillée Pour la plupart des programmeurs (bien s?r, je suis l'un d'entre eux), la programmation simultanée équivaut presque à l'ajout d'un verrou (Mutex) à la structure de données concernée. Par exemple, si nous avons besoin d'une pile prenant en charge la concurrence, le moyen le plus simple consiste à ajouter un verrou std::sync::Mutex à une pile à thread unique. (Arc est ajouté pour permettre à plusieurs threads d'être propriétaires de la pile) usestd::sync::{Mutex,Arc};#[derive(Clone)]structConcurrentStack{inner:Arc,}implConcurrentStack{pubfnnew()-> Self{

Dans le programme, j'ai créé 100 threads, et chaque thread a accumulé 10 000 opérations sur la variable partagée inc. Si elle est exécutée de manière synchrone, la valeur finale de inc devrait être de 1 000 000, mais nous savons qu'en multi-threading, le programme est exécuté simultanément. , c'est-à-dire que différents threads peuvent lire la même valeur dans la mémoire principale en même temps.

Ce numéro concerne l'analyse d'un problème ABA classique dans le domaine CAS. Je ne sais pas si vous l'avez rencontré dans le travail réel, mais c'est l'objet du test de connaissances sur la concurrence dans l'entretien. Si vous n'avez pas rencontré ce genre de problème, ma suggestion est d'exécuter vous-même le code ci-dessus.

1. Créez un nouveau projet Springboot et introduisez la dépendance org.jasig.cas.clientcas-client-support-springboot3.6.22. Configurez le package d'annotation @EnableCasClientcom.codetiler.demo;importorg.jasig.cas.client.boot.configuration. ActiverCasClient; importorg.springframework.boot.SpringApplication; importorg.spring
