目次
同期メソッドを使用する
同期されたステートメントまたはブロックを使用する
同期とは何ですか?
なぜ同期する必要があるのでしょうか?
概要
ホームページ Java &#&チュートリアル Java での synchronized キーワードの使用方法を理解するための例

Java での synchronized キーワードの使用方法を理解するための例

Oct 08, 2022 pm 04:02 PM
java

この記事では、java に関する関連知識を提供します。主に、同期メソッドの使用、同期ステートメントまたはブロックの使用、同期とは何か、同期が必要な理由など、 synchronized キーワードに関連する問題を紹介します。ぜひご覧ください。皆さんのお役に立てれば幸いです。

推奨学習: 「java ビデオ チュートリアル

日常の開発では、同期というキーワードがよく出てきます。同期というキーワードをご存知ですか?それの使い方?この記事ではそれを紹介します。

同期を使用するには 2 つの方法があります:

  • 同期メソッドを使用する
  • 同期ステートメントまたはブロックを使用する

同期メソッドを使用する

メソッドを同期するには、その宣言に synchronized キーワードを追加するだけです:

public class SynchronizedDemo {

    private int i = 0;

    public synchronized void add() {
        i++;
    }

    public synchronized void del() {
        i--;
    }

    public synchronized int getValue() {
        return i;
    }
}
ログイン後にコピー

上記のコードが示すように、3 つの同期メソッドがあります。

  • add()
  • del()
  • getValue()

各メソッドは、同じオブジェクトに対して同時に呼び出されます。たとえば、スレッドが add() を呼び出すと、最初のスレッドが add() メソッドの処理を完了するまで、他のスレッドはブロックされます。

同期されたステートメントまたはブロックを使用する

    public void del(int value){

        synchronized(this){
            this.i -= value;
        }
    }
ログイン後にコピー

上記のコードでは、同期されたコード ブロックを表す {} コードの前に synchronized が追加されています。

上記は synchronized キーワードを使用する 2 つの方法ですが、同期に関連する概念を簡単に紹介しましょう。

同期とは何ですか?

同期は、一貫性のない結果を避けるために、共有リソースへの複数のスレッドのアクセスを制御するプロセスです。同期を使用する主な目的は、スレッドの一貫性のない動作を回避し、スレッドの干渉を防ぐことです。

Java で synchronized キーワードを使用すると、同期効果を実現できます。synchronized はメソッドとブロックにのみ適用でき、変数やクラスには適用できません。

なぜ同期する必要があるのでしょうか?

最初にコードを見てみましょう:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronizedDemo.increment();
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

increment() メソッドが呼び出されるたびに、計算された値は 1 ずつ増加します:

Call 2 回で 2 が追加され、3 回で 3 が追加され、4 回で 4 が追加されます:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

次に、上記の例を拡張してスレッド Call を作成しましょうincrement() メソッドを 10 回実行:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        Thread thread = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                synchronizedDemo.increment();
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

この時点での計算結果は予想通り、結果は 10 です。

これは 1 つです。スレッド すべてがとても美しいですが、本当にそうなのでしょうか?マルチスレッド環境だとどうなるでしょうか?

マルチスレッドの状況をデモしてみましょう。

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

上記のコードに示すように、2 つのスレッド thread1 と thread2 を作成し、各スレッドが increment() を 1000 回呼び出しました。理論的には、最終的に出力される値は 2000 になるはずです。 thread1 は、increment() を 1000 回呼び出すと、値は 1000 になります。 thread2 は、increment() を 1000 回呼び出すと、値は 2000 になります。

これを実行して結果を見てみましょう:

結果は思ったものと異なります。2000 未満です。もう一度実行してみましょう:

結果はまだ 2000 未満です2000.

これはなぜでしょうか?

マルチスレッドは並列処理をサポートしているため、2 つのスレッドが同時にカウンターの値を取得することが常に可能であり、したがって両方のスレッドが同じカウンター値を取得することになります。そのため、この場合、インクリメントする代わりに、カウンタ値は 2 回増加しますが、増加するのは 1 回だけです。

では、この状況を回避するにはどうすればよいでしょうか?

この問題を解決するには、synchronized キーワードを使用します。

increment() メソッドに synchronized を追加するだけです:

public class SynchronizedDemo {

    int i;

    public synchronized void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

この時点でもう一度実行しましょう:

Asご覧のとおり、値は 2000 です。

計算回数を 10,000 回に増やします:

public class SynchronizedDemo {

    int i;

    public synchronized void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 10000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 10000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
ログイン後にコピー

実行結果は次のとおりです:

わかりました。少し同期すると、この問題は簡単に解決されることがわかります。

この背後にある原理は、スレッド 1 が increment() メソッドを実行すると、同期されているため、このメソッドは自動的にロックされるということです。現時点では、スレッド 1 のみがこのロックを保持しており、他のスレッドはスレッドが完了するまで待機することしかできません。 1 このロックを解放すると、スレッド 2 が通話に参加できるようになります。

同様に、スレッド 2 が increment() を呼び出すと、スレッド 2 がロックを取得し、スレッド 1 はスレッド 2 がロックを解放するまで待機します。計算が完了するまで、それだけです。このプロセス中、何も行われません。計算エラーが発生しました。

概要

  • synchronized キーワードは、ブロックまたはメソッドを同期させる唯一の方法です。
  • synchronized キーワードは、スレッド間で競合状態が発生しないようにするロック機能を提供します。ロックされた後、スレッドはメイン メモリからのデータの読み取りのみが可能になり、データの読み取り後、ロックを解放する前に書き込み操作をフラッシュします。
  • synchronized キーワードは、プログラム ステートメントの並べ替えを回避するのにも役立ちます。

推奨学習: 「Java ビデオ チュートリアル

以上がJava での synchronized キーワードの使用方法を理解するための例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホット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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのアームストロング数 Javaのアームストロング数 Aug 30, 2024 pm 04:26 PM

Java のアームストロング番号に関するガイド。ここでは、Java でのアームストロング数の概要とコードの一部について説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

See all articles