ホームページ  >  記事  >  Java  >  Java マルチスレッド プログラミングにおける synchronized キーワードの基本的な使用法の説明

Java マルチスレッド プログラミングにおける synchronized キーワードの基本的な使用法の説明

高洛峰
高洛峰オリジナル
2017-01-05 15:48:151405ブラウズ

マルチスレッド プログラミングにおいて、最も重要で最も懸念すべき問題は同期です。これが難しい点であり、核心です。
jdk の同期バージョンと揮発性バージョンから、jdk 1.5 (ReadLock、WriteLock、および ReentrantLock を実装) で提供される java.util.concurrent.locks パッケージの Lock インターフェースに至るまで、マルチスレッドの実装も段階的に成熟しています。 。

同期、それはどのようなメカニズムで制御されていますか?最初の反応はロックです。オペレーティング システムとデータベースを学習するときに、これに遭遇したことがあるはずです。 Java マルチスレッド プログラムでは、複数のプログラムが同じリソースをめぐって競合する場合、リソースの破損を防ぐために、リソースにアクセスする最初のスレッドにオブジェクト ロックが割り当てられ、後のスレッドはそのリソースが解放されるまで待つ必要があります。オブジェクトロック。

はい、Java スレッドの同期では、共有リソースの使用が最も考慮されます。

まず、スレッドの共有リソースについて学びましょう。
どのスレッド共有データを調整する必要があるかを理解します。
1. ヒープに保存されるインスタンス変数。 2. メソッド領域に保存されるクラス変数。

Java 仮想マシンがクラスをロードすると、オブジェクトのインスタンス変数またはクラス変数を保護するために、各オブジェクトまたはクラスがモニターに関連付けられます。もちろん、オブジェクトにインスタンス変数がない場合、またはクラスに変数がない場合は、モニターが使用されます。デバイスは何も監視しません。

上記のモニターの相互排他性を実現するために、仮想マシンはオブジェクトまたはクラスごとにロック (不可視ロックとも呼ばれます) を関連付けます。ここでは、クラス ロックもオブジェクト ロックを通じて実装されると説明します。クラスがロードされると、JVM はクラスごとに java.lang.Class のインスタンスを作成するため、オブジェクトがロックされると、このクラスのクラス オブジェクトもロックされます。

さらに、スレッドはオブジェクトを複数回ロックできます。これは複数のリリースに対応します。これは、オブジェクト ロックごとに JVM によって提供されるロック計算機であり、最後のロックは 1 を加算し、ロックが完了すると計算機を解放します。 0に達します。このオブジェクト ロックは JVM 内のモニターによって使用され、JVM によって自動的に生成されます。すべてのプログラマが自分で追加する必要はありません。

Java の同期原理を紹介した後、まず synchronized の使用について説明します。他の同期については後続の章で紹介します。

まずサンプルを実行してみましょう。

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
  
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
    
  @Override
  public synchronized void run() {  
    for(int i = 0;i<1000;i++){  
          System.out.println("NO." + threadnum + ":" + i ); 
    } 
    }  
    
    public static void main(String[] args) throws Exception {  
      for(int i=0; i<10; i++){ 
          new TestThread(i).start(); 
          Thread.sleep(1); 
      } 
    }  
}

実行結果:

NO.0:887 
NO.0:888 
NO.0:889 
NO.0:890 
NO.0:891 
NO.0:892 
NO.0:893 
NO.0:894 
NO.7:122 
NO.7:123 
NO.7:124

上記は、問題を説明するための単なる断片です。
注意深いお子様は、NO.0:894 の後に NO.7:122 が続いていることがわかります。これは、0 から 999 までではないことを意味します。
synchronized は synchronized メソッドまたは synchronized ブロックを実装できると言われていますが、なぜここで使用できないのですか?

まず、同期メカニズムを分析してみましょう。上記の例では、どのオブジェクトまたはクラスがロックされているのでしょうか。これには 2 つの変数があり、1 つは i で、もう 1 つは threadnum です。i はメソッドの内部であり、threadnum はプライベートです。
synchronized の動作メカニズムを見てみましょう:
Java プログラムでは、synchronized ブロックまたは synchronized メソッドを使用する場合、JVM がプログラムを処理している間、およびプログラムが監視に入ったときに、この領域が監視対象としてマークされます。領域にある場合は、オブジェクトまたはクラスが自動的にロックされます。

では、上記の例では、synchronized キーワードが使用された後、何がロックされるのでしょうか?
同期メソッドを使用した場合、メソッドを呼び出したインスタンスオブジェクト自体がオブジェクトロックとしてロックされます。この例では、10 個のスレッドが独自に作成した TestThread クラス オブジェクトを持っているため、取得されるオブジェクト ロックも独自のオブジェクト ロックであり、他のスレッドとは関係がありません。

メソッドのロックを実装するには、共有オブジェクトをロックする必要があります。

上記の例を変更して、もう一度見てみましょう:

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
  private String flag;  //标记 
    
  public TestThread(int threadnum,String flag) {  
       this.threadnum = threadnum;  
        this.flag = flag; 
    } 
    
  @Override
    public void run() {  
    synchronized(flag){ 
      for(int i = 0;i<1000;i++){  
              System.out.println("NO." + threadnum + ":" + i ); 
          }  
    } 
    }  
  
    public static void main(String[] args) throws Exception {  
      String flag = new String("flag"); 
      for(int i=0; i<10; i++){ 
          new TestThread(i,flag).start(); 
          Thread.sleep(1); 
      } 
    }  
}

は共有フラグも追加します。次に、同期ブロックを介してフラグ flag を同期します。これにより、共有オブジェクトをロックする条件が満たされます。
はい、走行結果は順調に出てきました。

同期ブロックを通じて、同期の目的を達成するためにオブジェクトロックを指定します。同期方法で実現できる他の方法はありますか?

同期の原則によると、共有オブジェクト ロックまたはクラス ロックを取得できれば、同期を実現できます。では、クラスロックを共有することでそれを実現できるでしょうか?

はい、静的同期メソッドを使用できます。静的メソッドの特性により、クラス オブジェクト自体からのみ呼び出すことができ、クラス オブジェクトをインスタンス化して呼び出すことはできません。そして、この静的メソッドのロックが取得できれば、このクラスロックも取得され、これらのクラスロックはすべてTestThreadクラスロックとなり、共有クラスロックを取得する目的は達成される。

実装コードは次のとおりです:

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 * @author ciding 
 * @createTime Dec 7, 2011 9:37:25 AM 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
    
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
    
  public static synchronized void staticTest(int threadnum) {  
    for(int i = 0;i<1000;i++){  
      System.out.println("NO." + threadnum + ":" + i ); 
    }  
  }  
  
  public static void main(String[] args) throws Exception {  
    for(int i=0; i<10; i++){ 
      new TestThread(i).start(); 
      Thread.sleep(1); 
    } 
  }  
    
  @Override
  public void run(){ 
    staticTest(threadnum); 
  } 
}

実行結果は 2 番目の例と若干同じです。


上記の内容では主に、同期ブロックと同期方法の 2 つの問題について説明します。
1. 同期ブロック: 取得されたオブジェクト ロックは、synchronized(flag) のフラグ オブジェクト ロックです。
2. 同期メソッド: 取得されるのは、メソッドが属するクラス オブジェクトとクラス オブジェクトのロックです。
静的同期方式、複数のスレッドで共有するため確実に同期されます。
静的同期方法の代わりに、シングルトンモードでのみ同期されます。


Java マルチスレッド プログラミングにおける synchronized キーワードの基本的な使用法の詳細については、PHP 中国語 Web サイトに注目してください。


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