ホームページ  >  記事  >  Java  >  Java 同期コード ブロックの詳細なサンプル コードの紹介

Java 同期コード ブロックの詳細なサンプル コードの紹介

黄舟
黄舟オリジナル
2017-02-28 10:47:182217ブラウズ

Java 同期ブロックは、コードのメソッドまたはブロックを同期させます。 Java 同期ブロックを使用すると、静的状態を回避できます。

この Java 同期キーワード

Java の同期ブロックは、synchronized キーワードを使用してマークされます。 Java の同期ブロックは、一部のオブジェクトで同期されます。すべてのオブジェクトで同期されたすべての同期ブロックは、同時に 1 つのスレッドによってのみ実行できます。同期ブロックに入ろうとする他のすべてのスレッドは、同期ブロック内のスレッドがブロックを離れるまでブロックされます。

synchronized キーワードを使用して、次の 4 つの異なるタイプのブロックをマークできます:


  1. インスタンス メソッド

  2. 静的メソッド

  3. インスタンス メソッドのコード ブロック

  4. 静的メソッドブロック

これらのブロックは異なるオブジェクトで同期されます。どの同期ブロック タイプが必要かは、特定のシナリオによって異なります。

同期されたインスタンス メソッド

例を次に示します:

  public synchronized void add(int value){
      this.count += value;
  }

メソッド内での synchronized キーワードの使用に注意してください。これにより、このメソッドが同期されていることを Java に伝えます。

Java の同期インスタンス メソッドは、このメソッドに属するインスタンス オブジェクト上で同期されます。したがって、各インスタンスには、異なるオブジェクト、つまり独自のインスタンスで同期される同期メソッドがあります。インスタンス同期メソッドを実行できるのは 1 つのスレッドだけであり、その後、1 つのスレッドが同期インスタンス メソッドを一度に 1 つずつ実行できます。インスタンスごとに 1 つのスレッド。

同期された静的メソッド

静的メソッドは、synchronized キーワードを使用するインスタンス メソッドと同様に、同期済みとしてマークされます。以下に例を示します。

  public static synchronized void add(int value){
      count += value;
  }

ここには、このメソッドが同期されていることを Java に伝えるための synchronized キーワードもあります。

同期された静的メソッドは、その静的メソッドが属するクラスのクラス オブジェクトで同期されます。 Java 仮想マシンの各クラスにはクラス オブジェクトが 1 つだけ存在するため、同じクラスの同期された静的メソッドを実行できるスレッドは 1 つだけです。

この静的同期メソッドが異なるクラスにある場合、スレッドは各クラスの内部静的同期メソッドを実行できます。どの静的同期メソッドを呼び出すかに関係なく、各クラスのスレッド。

インスタンスメソッド内の同期ブロック

メソッド全体を同期することはできません。場合によっては、メソッドの一部を同期した方が良い場合があります。メソッド内の Java 同期ブロックにより、これが可能になります。

ここに例があります:


  public void add(int value){

    synchronized(this){
       this.count += value;   
    }
  }

この例では、Java 同期ブロックを使用して、同期されたコードのブロックを構築します。同期メソッドの場合、このメソッドが実行されます。

この Java 同期ブロックがオブジェクトの一部でどのように構築されるかに注目してください。この例では、呼び出される add メソッドのインスタンスである「this」が使用されます。同期によって構築される括弧内のオブジェクトをモニターオブジェクトと呼びます。このコードは、モニター オブジェクトが同期であることを前提としています。同期されたインスタンス メソッドは、それが属するオブジェクトを監視オブジェクトとして使用します。

同じ監視対象オブジェクトの Java 同期ブロック内で実行できるスレッドは 1 つだけです。

以下の 2 つの例は、呼び出されたインスタンス上で同期されます。したがって、これらは同等です:


  public class MyClass {
  
    public synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }

  
    public void log2(String msg1, String msg2){
       synchronized(this){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }
  }


したがって、この例の 2 つの同期ブロックのうち 1 つを実行できるのは 1 つのスレッドだけです。

このために別のオブジェクトで同期される 2 番目の同期ブロックがあり、スレッドは内部で一度に 1 つのメソッドのみを実行できます。

静的メソッドの同期ブロック

ここに、静的メソッドとしての 2 つの同一のインスタンスがあります。これらのメソッドは、このメソッドが属するクラスのクラス オブジェクト内で同期されます:

  public class MyClass {

    public static synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }

  
    public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);  
       }
    }
  }


2 つのメソッドのいずれかを同時に実行できるのは 1 つのスレッドだけです。

MyClass.class には、別のオブジェクトで同期される 2 番目の同期ブロックがあり、スレッドは同時に 1 つの内部メソッドのみを実行できます。

Java 同期インスタンス

これは 2 つのスレッドを開始するインスタンスで、両方とも Counter の同じインスタンスの add メソッドを呼び出します。このメソッドは、それが属するインスタンス上で同期されるため、一度に同じインスタンスの add メソッドを呼び出すことができるスレッドは 1 つだけです。

  public class Counter{
     
     long count = 0;
    
     public synchronized void add(long value){
       this.count += value;
     }
  }


  public class CounterThread extends Thread{

     protected Counter counter = null;

     public CounterThread(Counter counter){
        this.counter = counter;
     }

     public void run() {
	for(int i=0; i<10; i++){
           counter.add(i);
        }
     }
  }


  public class Example {

    public static void main(String[] args){
      Counter counter = new Counter();
      Thread  threadA = new CounterThread(counter);
      Thread  threadB = new CounterThread(counter);

      threadA.start();
      threadB.start(); 
    }
  }


2 つのスレッドが作成されます。 2 つの同一の Counter インスタンスがコンストラクターに渡されます。 add メソッドはインスタンス メソッドであり、同期済みとしてマークされているため、add メソッドはインスタンス上で同期されます。したがって、一度に 1 つのスレッドだけがこの add メソッドを呼び出すことができます。他のスレッドは、最初のスレッドが add メソッドを終了するまで待機してから実行されます。

2 つのスレッドが 2 つの別々の Counter インスタンスを参照する場合、add メソッドを同時に呼び出しても問題はありません。この呼び出しは別のオブジェクト上で行われるため、このメソッド呼び出しも別のオブジェクト (このメソッドに属するオブジェクト) 上で同期されます。したがって、この呼び出しはブロックされません。以下に例を示します:

  public class Example {

    public static void main(String[] args){
      Counter counterA = new Counter();
      Counter counterB = new Counter();
      Thread  threadA = new CounterThread(counterA);
      Thread  threadB = new CounterThread(counterB);

      threadA.start();
      threadB.start(); 
    }
  }

注意这两个线程,他们不再引用相同的实例。counterA和counterB的add方法同步在它们自己的实例上。因此不会堵塞。

Java并发工具

这个synchronized机制是java的第一个途径对于访问同步访问被多线程共享的对象。但是这个synchronized机制不是最高级的。那就是为什么Java 5提供了一个并发工具类的集合去帮助开发者实现更细粒度的并发控制相对于synchronized而言。


 以上就是Java同步代码块的详细实例代码介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!


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