CodeGym /Java Blog /ランダム /スレッドの同期。同期オペレーター
John Squirrels
レベル 41
San Francisco

スレッドの同期。同期オペレーター

ランダム グループに公開済み
やあ!今日は引き続きマルチスレッド プログラミングの機能を検討し、スレッドの同期について話します。 スレッドの同期。 同期オペレーター - 1

Java における同期とは何ですか?

プログラミング領域の外では、2 つのデバイスまたはプログラムが連携できるようにする仕組みを意味します。たとえば、スマートフォンとコンピュータを Google アカウントと同期したり、Web サイトのアカウントをソーシャル ネットワーク アカウントと同期したりできるため、それらを使用してサインインできます。スレッドの同期も同様の意味を持ちます。スレッドが相互作用する仕組みです。お互い。前のレッスンでは、スレッドは互いに別々に存在し、動作していました。1 人は計算を実行し、2 人目は眠り、3 人目はコンソールに何かを表示しましたが、対話はしませんでした。実際のプログラムでは、このような状況はほとんどありません。複数のスレッドが同じデータ セットをアクティブに操作および変更できます。これにより問題が発生します。複数のスレッドが同じ場所 (テキスト ファイルやコンソールなど) にテキストを書き込むことを想像してください。この場合、ファイルまたはコンソールは共有リソースになります。スレッドは互いの存在を認識しないため、スレッド スケジューラによって割り当てられた時間内にできることすべてを書き込むだけです。最近のレッスンで、これがどのような結果につながるかの例を見ました。ここで思い出してみましょう: スレッドの同期。 同期オペレーター - 2その理由は、スレッドが相互にアクションを調整せずに共有リソース (コンソール) を操作しているという事実にあります。スレッド スケジューラが Thread-1 に時間を割り当てると、即座にすべてがコンソールに書き込まれます。他のスレッドが何を書き込めるか、まだ書き込めていないかは関係ありません。結果はご覧のとおり、憂鬱なものです。そのため、彼らはマルチスレッド プログラミングに特別な概念であるmutex (相互排他)を導入しました。 ミューテックスの目的特定の時点で 1 つのスレッドだけがオブジェクトにアクセスできるようにするメカニズムを提供することです。Thread-1 がオブジェクト A のミューテックスを取得すると、他のスレッドはオブジェクトにアクセスして変更できなくなります。他のスレッドは、オブジェクト A のミューテックスが解放されるまで待機する必要があります。これは人生の例です。あなたと他の 10 人の見知らぬ人が演習に参加していると想像してください。順番に自分のアイデアを表現し、何かについて話し合う必要があります。しかし、お互いに初めて会うので、頻繁にお互いの邪魔をして激怒しないように、「トーキングボール」を使用します。ボールを持っている人だけが話すことができます。こうすることで、最終的には良い、実りある議論ができるようになります。基本的に、ボールはミューテックスです。オブジェクトのミューテックスが 1 つのスレッドの手にある場合、他のスレッドはそのオブジェクトを操作できません。Objectクラス、つまり Java のすべてのオブジェクトにクラスがあることを意味します。

同期オペレーターの仕組み

新しいキーワード「 synchronized 」について学びましょう。コードの特定のブロックをマークするために使用されます。コード ブロックがsynchronizedキーワードでマークされている場合、そのブロックは一度に 1 つのスレッドによってのみ実行できます。同期はさまざまな方法で実装できます。たとえば、メソッド全体を同期するように宣言します。

public synchronized void doSomething() {

   // ...Method logic
}
または、何らかのオブジェクトを使用して同期が実行されるコード ブロックを作成します。

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
意味は簡単です。キーワードでマークされたコード ブロック内に 1 つのスレッドが入るとsynchronized、そのスレッドはオブジェクトのミューテックスを即座にキャプチャし、同じブロックまたはメソッドに入ろうとする他のすべてのスレッドは、前のスレッドが作業を完了してモニターを解放するまで待機することになります。 スレッドの同期。 同期オペレーター - 3ところで!このコースでは、 の例をすでに見てきましたがsynchronized、見た目は異なっていました。

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
そのトピックはあなたにとって新しいものです。そしてもちろん、構文に混乱が生じるでしょう。したがって、後でさまざまな書き方で混乱しないように、すぐに覚えてください。これら 2 つの書き方は同じことを意味します。

public void swap() {

   synchronized (this)
   {
       // ...Method logic
   }
}


public synchronized void swap() {

   }
}
最初のケースでは、メソッドに入った直後に、同期されたコード ブロックを作成します。これはthisオブジェクト、つまり現在のオブジェクトによって同期されます。synchronized2 番目の例では、キーワードをメソッド全体に適用します。これにより、同期に使用されるオブジェクトを明示的に指定する必要がなくなりました。メソッド全体がキーワードでマークされているため、メソッドはクラスのすべてのインスタンスに対して自動的に同期されます。どちらの方法がより良いかについての議論には立ち入りません。今のところ、最も好きな方法を選択してください :) 重要なことは、すべてのロジックが一度に 1 つのスレッドによって実行される場合にのみ、メソッドの同期を宣言できることを覚えておくことです。たとえば、次のメソッドを同期させるのは間違いですdoSomething()

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
ご覧のとおり、メソッドの一部には同期を必要としないロジックが含まれています。そのコードは複数のスレッドで同時に実行でき、すべての重要な場所は別のsynchronizedブロックに分離されます。後もう一つ。名前交換のレッスンの例を詳しく調べてみましょう。

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
注:同期は を使用して実行されますthis。つまり、特定のMyClassオブジェクトを使用します。Thread-12 つのスレッド (とThread-2) と 1 つのMyClass myClassオブジェクトあると仮定しますこの場合、 がThread-1を呼び出すとメソッドmyClass.swap()を呼び出そうとすると、ミューテックスが解放されるのを待っている間にメソッドがハングします。2 つのスレッドと 2 つのオブジェクト (とがある場合、スレッドは異なるオブジェクトに対して同期されたメソッドを簡単に同時に実行できます。最初のスレッドはこれを実行します。 myClass.swap()Thread-2MyClassmyClass1myClass2

myClass1.swap();
2 番目はこれを実行します。

myClass2.swap();
この場合、同期は特定のオブジェクトを使用して実行されるため、メソッドsynchronized内のキーワードはswap()プログラムの動作に影響しません。後者の場合、オブジェクトは 2 つあります。したがって、スレッドは相互に問題を引き起こしません。結局のところ、2 つのオブジェクトには 2 つの異なるミューテックスがあり、一方の取得は他方の取得とは独立しています

静的メソッドでの同期の特別な機能

しかし、静的メソッドを同期する必要がある場合はどうすればよいでしょうか?

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
ここでミューテックスがどのような役割を果たすのかは不明です。 結局のところ、各オブジェクトにはミューテックスがあることがすでに確認されています。しかし問題は、メソッドを呼び出すためにオブジェクトが必要ないことですMyClass.swap()。メソッドは静的です。それで、次は何でしょうか?:/ 実際のところ、ここでは問題ありません。Java の作成者がすべてを処理しました :) 重要な同時実行ロジックを含むメソッドが静的である場合、同期はクラス レベルで実行されます。より明確にするために、上記のコードを次のように書き換えることができます。

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
原則として、これは自分で考えることができます。オブジェクトがないため、同期メカニズムを何らかの方法でクラス自体に組み込む必要があります。そのとおりです。クラスを使用して同期できます。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION