Maison > Article > base de données > Quels sont les points de connaissances liés aux verrous Java et Mysql ?
Dans les programmes informatiques, les verrous sont utilisés pour des ressources exclusives. Ce n'est que lorsque le verrou est obtenu que le verrou peut être utilisé. les ressources correspondantes soient exploitées.
La mise en œuvre du verrouillage en bas de l'ordinateur s'appuie sur les instructions CAS (compare et swsp) fournies par le CPU. Pour une adresse mémoire, il. comparera la valeur d'origine et essaiera de modifier la valeur, si la valeur est modifiée avec succès indique si le verrou a été saisi.
Il existe 2 verrous couramment utilisés dans jvm
synchronisé est fourni par java Le le verrouillage par mot-clé peut verrouiller des objets, des classes et des méthodes.
Après JDK1.6, la synchronisation a été optimisée et le verrouillage biaisé et le mode de verrouillage léger ont été ajoutés. Désormais, la logique de fonctionnement du verrouillage synchronisé est la suivante :
biaise vers le fil qui a acquis le verrou en dernier lieu ". Ce mode améliore considérablement le débit d'un seul thread acquérant à plusieurs reprises le même verrou. Selon les responsables de Java, la plupart des conflits de verrouillage se produisent sur le même thread.
mise à niveau vers un verrou léger, la caractéristique d'un verrou léger est d'obtenir le verrou via spinCAS.
Le but de la conception légère des verrous est "à court terme, la contention des verrous peut être obtenue via spin CAS, et la consommation de rotation du processeur sur une courte période de temps est inférieure à la consommation de suspension et de réveil des threads."
Le verrouillage du poids est la logique synchronisée avant l'optimisation initiale.
Le nom complet d'AQS est AbstractQueueSynchronizer. Presque toutes les classes d'outils de JUC s'appuient sur AQS pour l'implémentation.
AQS est une classe abstraite en Java, mais c'est essentiellement l'implémentation d'une idée en Java.
La logique de mise en œuvre d'AQS est la suivante :
#🎜🎜 ##🎜 🎜#
Parce qu'il fournit des mécanismes tels que le délai d'attente et un fonctionnement flexible, il n'est pas sujet aux blocages. Si un blocage se produit, il sera plus difficile à résoudre car jstack n'affichera pas d'indicateur de blocage.Verrouillage d'intention
Le protocole de verrouillage d'intention est le suivant :
Avant qu'une transaction puisse obtenir un verrou partagé sur une ligne de la table, elle doit d'abord obtenir un verrou IS ou un verrou plus fort sur la table. Avant qu'une transaction puisse obtenir un verrou exclusif sur une ligne de la table, elle doit d'abord obtenir un verrou IX sur la table. Avant d'acquérir un verrou partagé ou exclusif sur un verrou de table, le verrou partagé sur la table doit être vérifié. Les règles d'exclusion mutuelle pour les verrous de table et les verrous d'intention sont les suivantes :X IX S IS
X Conflict Conflict Conflict ConflictIX Conflict Compatible Conflict Compatible#🎜 🎜#S Conflict Conflict Compatible Compatible
IS Conflict Compatible Compatible Compatible
Le but du verrouillage d'intention est le suivant : lors de l'acquisition d'un verrouillage de table, vous pouvez utiliser le verrouillage d'intention pour rapidement déterminer s'il peut être obtenu.
Parce que lors de l'acquisition d'un verrou au niveau de la ligne, le verrou d'intention correspondant sera acquis en premier, afin que les autres transactions puissent rapidement juger du verrou d'intention lors de l'acquisition des verrous de table, sans avoir besoin de chaque ligne va scanner. Une attention particulière est que les verrous d'intention peuvent être superposés, c'est-à-dire qu'il y en aura plusieurs. Par exemple, la transaction T1 acquiert le verrou d'intention IX1 et le verrou de niveau ligne X1, et la transaction T2 peut. acquérez toujours le verrou d'intention IX2 et le verrou de niveau ligne X1, de sorte que le verrou d'intention n'est vérifié qu'avant d'acquérir le verrou de niveau table.
Le verrouillage d'enregistrement prend effet sur l'index pour protéger les données de ligne contre la modification par d'autres transactions lorsque SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE.
Le verrouillage d'enregistrement prendra toujours effet lorsqu'il n'y a pas d'index, car innodb créera un index caché pour chaque table.
Le verrouillage d'enregistrement est le verrouillage de ligne le plus basique.
Le verrouillage des espaces prend effet sur l'index. Il est utilisé pour verrouiller la ligne après la valeur de l'index pour empêcher l'insertion. Il prendra effet lors de la sélection à partir de la table où index=? , alors index= sera verrouillé. 1Index lignes liées au nœud, empêcher d'autres transactions d'insérer des données.
Mais cela n'empêchera pas l'instruction de mise à jour, même si les données de mise à jour n'existent pas.
Ce verrou est une combinaison de verrouillage d'enregistrement et de verrouillage d'espacement. En bref, lors de la sélection dans la table où index=? pour la mise à jour, il y aura un verrouillage d'espacement pour empêcher l'insertion et le verrouillage d'enregistrement dans Empêcher la mise à jour. et suppression de cette donnée sur l'index. Cette clé suivante n'est qu'une généralisation de ces deux verrous, car ces deux verrous apparaissent généralement ensemble lors de la sélection pour la mise à jour.
Insérez des verrous d'intention, similaires aux verrous d'intention. Il s'agit d'un verrouillage d'espacement spécial, qui ne se produit pas lors de la sélection pour la mise à jour, mais se produit lorsque l'insertion se produit en même temps. Par exemple, lorsque deux transactions insèrent la plage d'index [4,7] en même temps, elles obtiennent l'intention. verrouillage de la plage en même temps. Ceci Lorsque la transaction est bloquée, par exemple, A : insert-5, B : insert-7, les deux transactions ne seront pas bloquées pour le moment.
Le verrouillage d'intention d'insertion est un verrouillage d'espacement spécial, conçu pour empêcher le blocage fréquent de l'insert dans des intervalles de verrouillage d'espacement normaux, tels que A : insert-5, B : insert-7, si aucun verrou d'intention n'est inséré, alors les deux. 5 et 7 tenteront d'acquérir le verrou d'espacement. À ce moment, la deuxième transaction sera bloquée. Cependant, en insérant le verrou d'intention, la deuxième transaction ne sera pas bloquée. bloc.
Verrouillage à incrémentation automatique, ce verrou est évidemment un verrou à insertion au niveau de la table, afin de garantir que la clé primaire de la table avec clé primaire à incrémentation automatique maintient l'auto-incrémentation atomique.
En ce qui concerne les serrures, chacun devrait mieux comprendre les principes et les modèles des différentes conceptions et opérations de serrures, afin qu'après avoir approfondi sa compréhension, il puisse les utiliser de manière plus approfondie et approfondie.
Comme nous le savons tous, les transactions MySQL ne sont d'aucune utilité pour empêcher les insertions répétées, et les index uniques présentent de nombreux défauts. Il est préférable de ne pas les utiliser en entreprise, donc de manière générale. , pour éviter la duplication. La manière courante d'insérer consiste à utiliser des verrous distribués, qui est une méthode d'écriture plus courante.
final WeekendNoticeReadCountDO weekendNoticeReadCountDO = weekendNoticeReadRepositoryService.selectByNoticeId(noticeRequestDTO.getNoticeId()); if (weekendNoticeReadCountDO == null) { final String lockKey = RedisConstant.LOCK_WEEKEND_READ_COUNT_INSERT + ":" + noticeRequestDTO.getNoticeId(); ClusterLock lock = clusterLockFactory.getClusterLockRedis( RedisConstant.REDIS_KEY_PREFIX, lockKey ); if (lock.acquire(RedisConstant.REDIS_LOCK_DEFAULT_TIMEOUT)) { //double check final WeekendNoticeReadCountDO weekendNoticeReadCountDO = weekendNoticeReadRepositoryService.selectByNoticeId(noticeRequestDTO.getNoticeId()); if (weekendNoticeReadCountDO == null) { try { lock.execute(() -> { WeekendNoticeReadCountDO readCountDO = new WeekendNoticeReadCountDO(); readCountDO.setNoticeId(noticeRequestDTO.getNoticeId()); readCountDO.setReadCount(1L); readCountDO.setCreateTime(new Date()); readCountDO.setUpdateTime(new Date()); weekendNoticeReadRepositoryService.insert(readCountDO); return true; }); } catch (ApiException err) { throw err; } catch (Exception e) { log.error("插入", e); throw new ApiException(ErrorEnum.SERVER_ERROR.getCode(), "服务端出错"); } } else { weekendNoticeReadRepositoryService.noticeCountAdd(weekendNoticeReadCountDO); } } else { log.warn("redis锁获取超时,key:{}", lockKey); throw new ApiException(ErrorEnum.SERVER_ERROR.getCode(), "服务器繁忙,请稍后重试"); } }
Après l'acquisition du verrou, il peut être acquis après avoir attendu. À ce moment, le thread précédent qui a libéré le verrou peut avoir inséré des données, donc à l'intérieur du verrou, il est encore nécessaire de vérifier si les données existent à nouveau.
Cette méthode d'écriture convient à la plupart des scénarios d'écriture qui nécessitent un caractère unique.
Comment éviter les impasses ? La méthode la plus simple et la plus efficace est la suivante : **Ne mettez pas le cadenas à l'intérieur de la serrure. En bref, il est préférable d'utiliser le cadenas seul, pas comme une poupée gigogne.
Faites également attention à certains verrous implicites, comme les bases de données.
Transaction A :
Insérez [5,7] et insérez le verrou d'intention.
sélectionnez la mise à jour [100,150], verrouillage de l'espace.
Transaction B :
sélectionnez la mise à jour [90 120], verrouillage de l'espace.
Insérez [4,6] et insérez le verrou d'intention.
À ce moment-là, dans un scénario concurrent, il peut arriver que A détienne le verrou d'écart de [5,7] et attend le verrou d'écart de la transaction B [90,120]. conduit à une impasse.
**
Lors de l'écriture de code métier et de la définition de certaines classes d'outils ou de classes de cache, il est facile d'être négligent et de provoquer des problèmes similaires.
Par exemple, lors de la création d'un cache statique, des méthodes telles que putIfAbsent dans ConcurrentHashMap ne sont pas utilisées et aucun verrou n'est utilisé pour le construire. Par conséquent, le thread ci-dessous est supprimé dès que le thread ci-dessus le met, ou le cache. est construit deux fois.
Ceci est également mentionné dans l'exemple de code du verrou Redis.
Le thread A acquiert le verrou. À ce moment, B et C attendent. Ensuite, le temps d'exécution de A est trop long, ce qui entraîne l'expiration du verrou et est automatiquement libéré. À ce moment, B acquiert le verrou et s'exécute joyeusement. . Ensuite, une fois que A a terminé l'exécution, le verrou est libéré. À ce moment-là, il n'a pas été jugé s'il était toujours détenu par lui-même, ce qui a entraîné la suppression du verrou détenu par B. À ce moment-là, C a de nouveau acquis le verrou. BC a été exécuté au même moment.
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!