在AbstractQueuedSynchronizer
类中维护了一个用volatile
修饰的state
状态,而这个状态有如下的两种修改方法:
state
的set
方法:
protected final void setState(int newState) {
state = newState;
}
CAS
方法:
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
那么,我的疑问来了,不是说volatile
修饰的变量在多线程的单操作中,能够保证其写后读的可见性,即能保证线程安全,为什么还提供了CAS
操作能保证线程安全呢?还是我的理解有问题呢?谢谢各位大牛了!
Il n'y a pas de conflit. setState est juste une opération d'écriture et ne se soucie pas de l'état d'origine. Par exemple, l'état était à l'origine 0. Le thread 1 et le thread 2 lisent respectivement la valeur 0. puis le thread 2 prévoit de le définir sur 2, ce qui peut réussir. Bien que l'état soit déjà 1 et que le thread 2 le sache également, cela n'a pas d'importance. Le thread 2 le définit simplement sur 2. La méthode suivante ne fonctionnera pas.
Oui, il y a un problème avec votre compréhension.
Être capable de garantir la visibilité ne signifie pas que la sécurité des fils peut être garantie. La visibilité et la sécurité des threads ne sont pas le même concept.
l'opération cas peut être divisée en plusieurs petites opérations
Comparez les valeurs actuelles des variables attendues et d'état Si elles sont identiques, passez à l'étape 2. Si elles sont différentes, la méthode se termine.
Attribuer une valeur à la mise à jour de l'état
Si ces deux opérations sont appelées simultanément par plusieurs threads, il y aura des problèmes de sécurité des threads.
La méthode cas utilise ici l'instruction cas du CPU, qui est une opération atomique. Les problèmes de concurrence peuvent être évités.
En bref :
Si vous ne vous fiez pas à la valeur d'origine, vous pouvez utiliser set
Si vous vous fiez à la valeur d'origine, vous pouvez utiliser cas pour la définir. C’est en soi un verrou optimiste.