検索
ホームページJava&#&チュートリアルJavaリライトロックの設計構造と詳細は何ですか

    はじめに

    一部の面接官は、学生にロックの原理を説明した後に新しいロックを書き直すよう求め、現場に立ち会ってもらうことを好みます。一般的なアイデアとコード ロジックをホワイトボードに書きます。この種の面接の質問は非常に難しいです。個人的には、次の 2 つの部分に焦点が当てられていると思います:

    ロック原理をどのように理解したか調べてください。まだ理解していない場合は、ソースコードを解釈すれば、オンラインの記事を読んだり、インタビューの質問を覚えたりするだけで大​​まかな原理はわかりますが、実際にソースコードを読んでいない限り、その場でロックの実装コードを書くのは困難です。ロックに関連するプロジェクトの経験がある;

    作成する必要はなく、Java ロックの既存の API を模倣して書き直すだけで済みます。

    ソース コードを読んだことがあれば、この質問は非常に簡単です。使い慣れたロックを選択して模倣することができます。

    1. 要件

    一般に、ロックをカスタマイズするときは、要件に基づいてロックを定義します。何もないところからロックを定義することは不可能です。共有ロックに関しては、多くのものが思い浮かぶかもしれません。シナリオ、たとえば、共有リソースの読み取りロックを共有できる、データベース リンクへの共有アクセスなど、たとえば、ソケット サーバー上のリンクの数を共有できるなど、多くのシナリオがあります。データベース リンクにアクセスしてロックを定義します。

    2. 詳細な設計

    データベースはスタンドアロンの mysql であり、10 個の接続しかサポートできないと仮定します (以下の前提はすべて前提です)。データベース接続を作成するときは、次を使用します。オリジナルの JDBC このように、JDBC を使用してリンクを作成するプロセスをカプセル化するインターフェイスを使用します。このインターフェイスに Create Link Interface という名前を付けます。

    共有アクセス データベース リンクの全体的な要件は次のとおりです: すべてのリクエストを合わせた mysql リンクの数は 10 (両端を含む) を超えることはできません。10 を超えると、エラーが直接報告されます。

    これに関連して、以下に示すように設計を実行しました。

    Javaリライトロックの設計構造と詳細は何ですか

    この設計の最も重要な部分は、それを介してロックを取得できるかどうかです。 mysql リンクを取得できるかどうかを判断するには、ロックを取得できる場合はリンクを取得でき、そうでない場合はエラーが直接報告されます。

    次に、実装されたコードを見てみましょう:

    2.1. ロックの定義

    最初にロックを定義する必要があり、それには 2 つの要素が必要です:

    ロックの定義: シンクロナイザー Sync; ロックによって提供されるロックおよびロック解除の方法。

    共有ロックのコード実装は次のとおりです。

    // 共享不公平锁
    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);
      }
    }

    上記のコードからわかるように、ロックのロックと解放の実装は、基礎となるシンクロナイザー Sync の実装に依存しています。

    注意する必要がある唯一のことは、ロックには主に 2 つの側面で優れた API 仕様が必要であるということです。

    API で必要なのは、次のときにどのようなパラメーターを渡す必要があるかです。 ShareLock を初期化するときは、共有可能なロックの最大数を渡す必要があります。

    独自の機能を定義する必要があります。つまり、各メソッドの入力パラメータと出力パラメータを定義する必要があります。 ShareLock の実装には、ロックのロックと解放のための入力パラメータはありません。これらはメソッド内でハードコーディングされています 1。つまり、メソッドが実行されるたびに、ロックは 1 回のみロックまたは解放されます。出力パラメータはブール値で、true はロックまたはロックの解放が成功したことを意味し、false は失敗を示し、最下位層は不当な同期ロックを使用します。

    上記の考え方には方法論があります。つまり、問題を考えるとき、次の 2 つの側面から始めることができます。API とは何か? API にはどのような機能がありますか?

    2.2. シンクロナイザーの定義 Sync

    Sync は AQS を直接継承しており、コードは次のとおりです:

    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;
          }
        }
      }
    }

    コード全体は比較的明確ですが、注意する必要がある点は次のとおりです。

    入力パラメータが不正かどうか、ロックを解除したときに予想される不正な状態が発生するかどうかなどの境界判断、思考の厳密さを反映して判断する必要がある;

    追加 ロックを同時にロックまたは解放するときに再試行が成功することを保証するには、ロックとロックの解放をスピン CAS の形式にする必要があります。スピン用に書く場合は、適切なタイミングでリターンすることと、無限ループにならないように注意する必要があります。CAS メソッドは AQS から提供されています。自分で書かないでください。自分で書いた CAS メソッドはアトミック性を保証できません。

    2.3. ロックが取得できるかどうかによって、リンクが取得できるかどうかを判断します。

    ロックを定義した後、ロックと Mysql リンクの取得を組み合わせる必要があります。 MysqlConnection と呼ばれる Mysql リンク ツール クラスは、主に 2 つの主要な機能を担当します:

    JDBC を介した Mysql とのリンクの確立;

    Mysql リンクの総数が超過しないようにロックと組み合わせる10 リクエストが大きすぎる場合。

    まず、MysqlConnection 初期化コードを見てみましょう:

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

    初期化中に、リンクの最大数を指定し、この値をロックに渡す必要があることがわかります。リンクの最大数が ShareLock ロックの状態値であるためです。

    次に、1 を完了するために、プライベート メソッドを作成しました:

    // 得到一个 mysql 链接,底层实现省略
    private Connection getConnection(){}

    次に、2 を実装しました。コードは次のとおりです:

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

    逻辑也比较简单,加锁时,如果获得了锁,就能返回 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("模仿结束");
    }

    以上代码逻辑如下:

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

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

    Javaリライトロックの設計構造と詳細は何ですか

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

    以上がJavaリライトロックの設計構造と詳細は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明
    この記事は亿速云で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
    Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Apr 25, 2025 am 12:23 AM

    javaispopularforsoss-platformdesktopapplicationsduetoits "writeonce、runaynay" philosophy.1)itusesbytecodatiTatrunnanyjvm-adipplatform.2)ライブラリリケンディンガンドジャヴァフククレアティック - ルルクリス

    Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Apr 25, 2025 am 12:22 AM

    Javaでプラットフォーム固有のコードを作成する理由には、特定のオペレーティングシステム機能へのアクセス、特定のハードウェアとの対話、パフォーマンスの最適化が含まれます。 1)JNAまたはJNIを使​​用して、Windowsレジストリにアクセスします。 2)JNIを介してLinux固有のハードウェアドライバーと対話します。 3)金属を使用して、JNIを介してMacOSのゲームパフォーマンスを最適化します。それにもかかわらず、プラットフォーム固有のコードを書くことは、コードの移植性に影響を与え、複雑さを高め、パフォーマンスのオーバーヘッドとセキュリティのリスクをもたらす可能性があります。

    プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?Apr 25, 2025 am 12:12 AM

    Javaは、クラウドネイティブアプリケーション、マルチプラットフォームの展開、および言語間の相互運用性を通じて、プラットフォームの独立性をさらに強化します。 1)クラウドネイティブアプリケーションは、GraalvmとQuarkusを使用してスタートアップ速度を向上させます。 2)Javaは、埋め込みデバイス、モバイルデバイス、量子コンピューターに拡張されます。 3)Graalvmを通じて、JavaはPythonやJavaScriptなどの言語とシームレスに統合して、言語間の相互運用性を高めます。

    Javaの強力なタイピングは、プラットフォームの独立性にどのように貢献しますか?Javaの強力なタイピングは、プラットフォームの独立性にどのように貢献しますか?Apr 25, 2025 am 12:11 AM

    Javaの強力なタイプ化されたシステムは、タイプの安全性、統一タイプの変換、多型を通じてプラットフォームの独立性を保証します。 1)タイプの安全性は、コンパイル時間でタイプチェックを実行して、ランタイムエラーを回避します。 2)統一された型変換ルールは、すべてのプラットフォームで一貫しています。 3)多型とインターフェイスメカニズムにより、コードはさまざまなプラットフォームで一貫して動作します。

    Javaネイティブインターフェイス(JNI)がプラットフォームの独立性をどのように妥協できるかを説明します。Javaネイティブインターフェイス(JNI)がプラットフォームの独立性をどのように妥協できるかを説明します。Apr 25, 2025 am 12:07 AM

    JNIはJavaのプラットフォームの独立を破壊します。 1)JNIは特定のプラットフォームにローカルライブラリを必要とします。2)ローカルコードをターゲットプラットフォームにコンパイルおよびリンクする必要があります。3)異なるバージョンのオペレーティングシステムまたはJVMは、異なるローカルライブラリバージョンを必要とする場合があります。

    Javaのプラットフォームの独立性を脅かしたり強化したりする新しいテクノロジーはありますか?Javaのプラットフォームの独立性を脅かしたり強化したりする新しいテクノロジーはありますか?Apr 24, 2025 am 12:11 AM

    新しいテクノロジーは、両方の脅威をもたらし、Javaのプラットフォームの独立性を高めます。 1)Dockerなどのクラウドコンピューティングとコンテナ化テクノロジーは、Javaのプラットフォームの独立性を強化しますが、さまざまなクラウド環境に適応するために最適化する必要があります。 2)WebAssemblyは、Graalvmを介してJavaコードをコンパイルし、プラットフォームの独立性を拡張しますが、パフォーマンスのために他の言語と競合する必要があります。

    JVMのさまざまな実装は何ですか、そしてそれらはすべて同じレベルのプラットフォームの独立性を提供しますか?JVMのさまざまな実装は何ですか、そしてそれらはすべて同じレベルのプラットフォームの独立性を提供しますか?Apr 24, 2025 am 12:10 AM

    JVMの実装が異なると、プラットフォームの独立性が得られますが、パフォーマンスはわずかに異なります。 1。OracleHotspotとOpenJDKJVMは、プラットフォームの独立性で同様に機能しますが、OpenJDKは追加の構成が必要になる場合があります。 2。IBMJ9JVMは、特定のオペレーティングシステムで最適化を実行します。 3. Graalvmは複数の言語をサポートし、追加の構成が必要です。 4。AzulzingJVMには、特定のプラットフォーム調整が必要です。

    プラットフォームの独立性は、開発コストと時間をどのように削減しますか?プラットフォームの独立性は、開発コストと時間をどのように削減しますか?Apr 24, 2025 am 12:08 AM

    プラットフォームの独立性により、開発コストが削減され、複数のオペレーティングシステムで同じコードセットを実行することで開発時間を短縮します。具体的には、次のように表示されます。1。開発時間を短縮すると、1セットのコードのみが必要です。 2。メンテナンスコストを削減し、テストプロセスを統合します。 3.展開プロセスを簡素化するための迅速な反復とチームコラボレーション。

    See all articles

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    Video Face Swap

    Video Face Swap

    完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

    ホットツール

    ZendStudio 13.5.1 Mac

    ZendStudio 13.5.1 Mac

    強力な PHP 統合開発環境

    SublimeText3 英語版

    SublimeText3 英語版

    推奨: Win バージョン、コードプロンプトをサポート!

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

    WebStorm Mac版

    WebStorm Mac版

    便利なJavaScript開発ツール