Table des matières
Introduction
1. Exigences
2. Conception détaillée
2.1 Définir le verrou
2.2. Définir le synchroniseur Sync
Une fois le verrou défini, nous devons combiner le verrou avec l'obtention du lien Mysql. Nous avons écrit une classe d'outil de lien Mysql appelée MysqlConnection, qui. est principalement responsable de deux grandes fonctionnalités :
3、测试
Maison Java javaDidacticiel Quelle est la structure de conception et les détails du verrouillage de réécriture Java

Quelle est la structure de conception et les détails du verrouillage de réécriture Java

Apr 18, 2023 pm 05:22 PM
java

    Introduction

    Certains intervieweurs aiment demander aux étudiants de réécrire une nouvelle serrure après avoir expliqué le principe de la serrure, et vous demandent d'écrire l'idée générale et la logique du code sur le tableau blanc. Ce genre d'entretien La question est assez. difficile. Personnellement, je pense qu'il se concentre sur deux parties :

    Examinez d'où vient votre compréhension du principe de verrouillage. Si vous n'avez pas lu le code source, lisez simplement les articles en ligne, ou Les questions d'entretien au dos peuvent également expliquer le général. principe, mais il vous est difficile d'écrire un code d'implémentation de verrouillage sur place, à moins d'avoir vraiment vu le code source, ou d'avoir de l'expérience dans des projets liés au verrouillage

    Nous n'avons pas besoin de créer, nous juste cela ; doit être réécrit pour imiter l'API existante dans le verrouillage Java.

    Si vous avez lu le code source, cette question est très simple. Vous pouvez choisir une serrure que vous connaissez à imiter.

    1. Exigences

    Généralement, lors de la personnalisation des verrous, nous les définissons en fonction des exigences. Il est impossible de définir des verrous à partir de rien. Lorsqu'il s'agit de verrous partagés, vous pouvez penser à de nombreux scénarios, comme pour les ressources partagées. Les verrous de lecture peuvent être partagés, comme l'accès partagé aux liens de base de données. Par exemple, le nombre de liens sur le serveur Socket peut être partagé. Il existe de nombreux scénarios. Nous choisissons le scénario d'accès partagé aux liens de base de données pour définir un verrou.

    2. Conception détaillée

    Supposons (les hypothèses suivantes sont toutes des hypothèses) que notre base de données est un MySQL autonome, qui ne peut prendre en charge que 10 connexions. Lors de la création d'un lien de base de données, nous utilisons la méthode JDBC la plus primitive, et nous. utiliser une interface. JDBC encapsule le processus de création d'un lien. Nous nommons cette interface : Create Link Interface.

    Les exigences globales pour les liens de base de données à accès partagé sont les suivantes : le nombre de liens mysql pour toutes les requêtes combinées ne peut pas dépasser 10 (inclus). Une fois qu'il dépasse 10, une erreur sera signalée directement.

    Dans ce contexte, nous avons conçu l'image suivante :

    Quelle est la structure de conception et les détails du verrouillage de réécriture Java

    La partie la plus critique de cette conception est que nous décidons si nous pouvons obtenir le lien mysql en fonction de si nous pouvons obtenir le verrou. alors vous pouvez obtenir le lien, sinon une erreur sera signalée directement.

    Jetons ensuite un œil au code implémenté :

    2.1 Définir le verrou

    Nous devons d'abord définir un verrou. La définition nécessite deux éléments :

    Définition du verrou : synchroniseur de verrouillage fourni en externe. Méthodes de verrouillage. et déverrouillage.

    L'implémentation du code du verrou partagé est la suivante :

    // 共享不公平锁
    public class ShareLock implements Serializable{
    	// 同步器
      private final Sync sync;
      // 用于确保不能超过最大值
      private final int maxCount;
      /**
       * 初始化时给同步器 sync 赋值
       * count 代表可以获得共享锁的最大值
       */
      public ShareLock(int count) {
        this.sync = new Sync(count);
        maxCount = count;
      }
      /**
       * 获得锁
       * @return true 表示成功获得锁,false 表示失败
       */
      public boolean lock(){
        return sync.acquireByShared(1);
      }
      /**
       * 释放锁
       * @return true 表示成功释放锁,false 表示失败
       */
      public boolean unLock(){
        return sync.releaseShared(1);
      }
    }
    Copier après la connexion

    Comme le montre le code ci-dessus, l'implémentation du verrouillage et de la libération des verrous repose sur l'implémentation sous-jacente du synchroniseur Sync.

    La seule chose à noter est que le verrou doit spécifier les spécifications de l'API, principalement sous deux aspects :

    Ce que l'API exige, ce sont les paramètres que vous devez me transmettre lorsque le verrou est initialisé. est initialisé, vous devez passer le maximum Le nombre de verrous partageables

    Doit définir ses propres capacités, c'est-à-dire définir les paramètres d'entrée et les paramètres de sortie de chaque méthode. Dans l'implémentation de ShareLock, il n'y a pas de paramètres d'entrée pour verrouiller et libérer les verrous. Ils sont codés en dur 1 dans la méthode, ce qui signifie que chaque fois que la méthode est exécutée, le verrou ne peut être verrouillé qu'une seule fois ou libéré une seule fois. Le paramètre est une valeur booléenne, et true signifie que l'ajout du verrouillage ou de la libération du verrou est réussi, false indique un échec et la couche inférieure utilise des verrous injustes de synchronisation.

    La façon de penser ci-dessus a une méthodologie, c'est-à-dire que lorsque nous réfléchissons à un problème, nous pouvons partir de deux aspects : Qu'est-ce qu'une API ? Quelles sont les capacités de l'API ?

    2.2. Définir le synchroniseur Sync

    Sync hérite directement d'AQS. Le code est le suivant :

    class Sync extends AbstractQueuedSynchronizer {
       // 表示最多有 count 个共享锁可以获得
      public Sync(int count) {
        setState(count);
      }
      // 获得 i 个锁
      public boolean acquireByShared(int i) {
        // 自旋保证 CAS 一定可以成功
        for(;;){
          if(i<=0){
            return false;
          }
          int state = getState();
          // 如果没有锁可以获得,直接返回 false
          if(state <=0 ){
            return false;
          }
          int expectState = state - i;
          // 如果要得到的锁不够了,直接返回 false
          if(expectState < 0 ){
            return false;
          }
          // CAS 尝试得到锁,CAS 成功获得锁,失败继续 for 循环
          if(compareAndSetState(state,expectState)){
            return true;
          }
        }
      }
      // 释放 i 个锁
      @Override
      protected boolean tryReleaseShared(int arg) {
        for(;;){
          if(arg<=0){
            return false;
          }
          int state = getState();
          int expectState = state + arg;
          // 超过了 int 的最大值,或者 expectState 超过了我们的最大预期
          if(expectState < 0 || expectState > maxCount){
            log.error("state 超过预期,当前 state is {},计算出的 state is {}",state
            ,expectState);
            return false;
          }
          if(compareAndSetState(state, expectState)){
            return true;
          }
        }
      }
    }
    Copier après la connexion

    L'ensemble du code est relativement clair. Ce à quoi nous devons prêter attention est :

    Le jugement de la frontière, tel que. si le paramètre d'entrée est illégal, cela ne se produira-t-il pas lorsque le verrou sera libéré ? Il y aura des problèmes de limites tels qu'un état illégal. Nous devons juger de tels problèmes et refléter la rigueur de la réflexion ; vous devez utiliser le formulaire for spin + CAS pour vous assurer que lors de l'ajout simultané Lorsque vous verrouillez ou relâchez le verrou, vous pouvez réessayer avec succès. Lors de l'écriture pour spin, nous devons faire attention à revenir au moment approprié et à ne pas provoquer de boucle infinie. La méthode CAS a été fournie par AQS. Ne l'écrivez pas vous-même. La méthode CAS que nous écrivons nous-mêmes ne peut pas garantir l'atomicité.

    2.3. La possibilité d'obtenir le lien est déterminée par la possibilité d'obtenir le verrou

    Une fois le verrou défini, nous devons combiner le verrou avec l'obtention du lien Mysql. Nous avons écrit une classe d'outil de lien Mysql appelée MysqlConnection, qui. est principalement responsable de deux grandes fonctionnalités :

    Établir un lien avec Mysql via JDBC

    Combiné avec un verrou pour empêcher le nombre total de liens Mysql de dépasser 10 lorsque la requête est trop volumineuse ;

    Tout d'abord, jetons un œil au code d'initialisation de MysqlConnection :

    public class MysqlConnection {
      private final ShareLock lock;
      // maxConnectionSize 表示最大链接数
      public MysqlConnection(int maxConnectionSize) {
        lock = new ShareLock(maxConnectionSize);
      }
    }
    Copier après la connexion

    Nous pouvons voir que lors de l'initialisation, nous devons spécifier le nombre maximum de liens, puis transmettre cette valeur au verrou, car le nombre maximum de liens est l'état de la valeur du verrou ShareLock.

    Puis afin de compléter 1, nous avons écrit une méthode privée :

    // 得到一个 mysql 链接,底层实现省略
    private Connection getConnection(){}
    Copier après la connexion

    Puis nous avons implémenté 2, le code est le suivant :

    // 对外获取 mysql 链接的接口
    // 这里不用try finally 的结构,获得锁实现底层不会有异常
    // 即使出现未知异常,也无需释放锁
    public Connection getLimitConnection() {
      if (lock.lock()) {
        return getConnection();
      }
      return null;
    }
    // 对外释放 mysql 链接的接口
    public boolean releaseLimitConnection() {
      return lock.unLock();
    }
    Copier après la connexion

    逻辑也比较简单,加锁时,如果获得了锁,就能返回 Mysql 的链接,释放锁时,在链接关闭成功之后,调用 releaseLimitConnection 方法即可,此方法会把锁的 state 状态加一,表示链接被释放了。

    以上步骤,针对 Mysql 链接限制的场景锁就完成了。

    3、测试

    锁写好了,接着我们来测试一下,我们写了一个测试的 demo,代码如下:

    public static void main(String[] args) {
      log.info("模仿开始获得 mysql 链接");
      MysqlConnection mysqlConnection = new MysqlConnection(10);
      log.info("初始化 Mysql 链接最大只能获取 10 个");
      for(int i =0 ;i<12;i++){
        if(null != mysqlConnection.getLimitConnection()){
          log.info("获得第{}个数据库链接成功",i+1);
        }else {
          log.info("获得第{}个数据库链接失败:数据库连接池已满",i+1);
        }
      }
      log.info("模仿开始释放 mysql 链接");
      for(int i =0 ;i<12;i++){
        if(mysqlConnection.releaseLimitConnection()){
          log.info("释放第{}个数据库链接成功",i+1);
        }else {
          log.info("释放第{}个数据库链接失败",i+1);
        }
      }
      log.info("模仿结束");
    }
    Copier après la connexion

    以上代码逻辑如下:

    获得 Mysql 链接逻辑:for 循环获取链接,1~10 都可以获得链接,11~12 获取不到链接,因为链接被用完了;释放锁逻辑:for 循环释放链接,1~10 都可以释放成功,11~12 释放失败。

    我们看下运行结果,如下图:

    Quelle est la structure de conception et les détails du verrouillage de réécriture Java

    从运行的结果,可以看出,我们实现的 ShareLock 锁已经完成了 Mysql 链接共享的场景了。

    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!

    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

    Outils d'IA chauds

    Undresser.AI Undress

    Undresser.AI Undress

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

    AI Clothes Remover

    AI Clothes Remover

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

    Undress AI Tool

    Undress AI Tool

    Images de déshabillage gratuites

    Clothoff.io

    Clothoff.io

    Dissolvant de vêtements AI

    Video Face Swap

    Video Face Swap

    Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

    Outils chauds

    Bloc-notes++7.3.1

    Bloc-notes++7.3.1

    Éditeur de code facile à utiliser et gratuit

    SublimeText3 version chinoise

    SublimeText3 version chinoise

    Version chinoise, très simple à utiliser

    Envoyer Studio 13.0.1

    Envoyer Studio 13.0.1

    Puissant environnement de développement intégré PHP

    Dreamweaver CS6

    Dreamweaver CS6

    Outils de développement Web visuel

    SublimeText3 version Mac

    SublimeText3 version Mac

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

    Nombre parfait en Java Nombre parfait en Java Aug 30, 2024 pm 04:28 PM

    Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

    Weka en Java Weka en Java Aug 30, 2024 pm 04:28 PM

    Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

    Numéro de Smith en Java Numéro de Smith en Java Aug 30, 2024 pm 04:28 PM

    Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

    Questions d'entretien chez Java Spring Questions d'entretien chez Java Spring Aug 30, 2024 pm 04:29 PM

    Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

    Break or Return of Java 8 Stream Forach? Break or Return of Java 8 Stream Forach? Feb 07, 2025 pm 12:09 PM

    Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

    Horodatage à ce jour en Java Horodatage à ce jour en Java Aug 30, 2024 pm 04:28 PM

    Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

    Programme Java pour trouver le volume de la capsule Programme Java pour trouver le volume de la capsule Feb 07, 2025 am 11:37 AM

    Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

    Créer l'avenir : programmation Java pour les débutants absolus Créer l'avenir : programmation Java pour les débutants absolus Oct 13, 2024 pm 01:32 PM

    Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.

    See all articles