ホームページ  >  記事  >  Java  >  Javaマルチスレッドプログラミングにおけるスレッド同期方法の詳細説明

Javaマルチスレッドプログラミングにおけるスレッド同期方法の詳細説明

高洛峰
高洛峰オリジナル
2017-01-05 16:32:071454ブラウズ

1. マルチスレッド同期:
1.1. 同期メカニズム:
マルチスレッドでは、限られたリソースにアクセスしようとする複数のスレッドが存在する可能性があるため、これを防止する必要があります。したがって、同期メカニズムが導入されています。スレッドがリソースを使用すると、そのリソースはロックされ、ロックが解除されるまで他のスレッドはそのリソースにアクセスできなくなります。

1.2. 共有メンバー変数の例:
メンバー変数とローカル変数:
メンバー変数:

変数がメンバー変数の場合、複数のスレッドが同じオブジェクトのメンバー変数を操作し、これらの複数のスレッドが共有されます。メンバー変数。

ローカル変数:

変数がローカル変数の場合、複数のスレッドが同じオブジェクト上で動作し、各スレッドはローカル変数のコピーを持つことになります。それらの間のローカル変数は相互に影響しません。

以下は例です:
Runnableを実装するスレッドクラス:

class MyThread3 implements Runnable{
 
 //两个线程操作同一个对象,共享成员变量
 //int i;
 @Override
 public void run() {
  //两个线程操作同一个对象,各自保存局部变量的拷贝
  int i = 0;
  while(i<100){
   System.out.println(i);
   i++;
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}

mainメソッドで同じオブジェクトを操作するために2つのスレッドを使用します:

public static void main(String[] args) {
 
 MyThread3 myThread = new MyThread3();
 //下面两个线程对同一个对象(Runnable的实现类对象)进行操作
 Thread thread = new Thread(myThread);
 Thread thread2 = new Thread(myThread);
 //各自保存局部变量的拷贝,互不影响,输出200个数字
 thread.start();
 thread2.start();
}

iをメンバー変数に変更すると、100個の数値が出力されます。

1.3. 共有リソースによる読み取りエラー
以下は、2 つのスレッドが Number オブジェクトを共有し、データの読み取りと書き換えを行うときに、繰り返しの読み取り操作が検出される例です。

まず第一に、Number クラスを作成します:

class Number{
 private int number = 10;
 public String getNumber(int i){
  if(number > 0){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   number -= i;
   return "取出"+i+"成功,剩余数量:"+number;
  }
  return "取出"+i+"失败,剩余数量:"+number;
 }
}

Thread クラス。スレッド クラスのプライベート プロパティには Number クラスへの参照が含まれます。

class MyThread4 extends Thread{
 
 //两个线程操作同一个对象,共享成员变量
 Number number;
 public MyThread4(Number number){
  this.number = number;
 }
 @Override
 public void run() {
  System.out.println(number.getNumber(8));
 }
}

main 関数に 2 つのスレッド クラスを作成し、同じ Number への参照を含みます。クラスインスタンス:

public static void main(String[] args) {
 
 Number number = new Number();
 //两个线程操作同一个对象,共享对象number的成员变量number
 MyThread4 myThread = new MyThread4(number);
 MyThread4 myThread2 = new MyThread4(number);
 myThread.start();
 myThread2.start();
}

このように、最初のスレッドが Number の数値変数を読み取ると、まずそれを保存し、次に 2 番目のスレッドが数値変数を読み取り、それを保存します。スレッドは同じ数値を保存して時間を変更するため、同じ数値が 2 回変更されることになります。

2. 同期メカニズムの実装:

Synchronized は、マルチスレッド同時プログラミングでは常にベテランの役割を果たしていますが、Java SE1.6 では Synchronized のさまざまな最適化が行われています。

Java のすべてのオブジェクトはロックとして使用できます。

同期メソッドの場合、ロックは現在のインスタンス オブジェクトです。

静的同期メソッドの場合、ロックは現在のオブジェクトの Class オブジェクトです。
同期メソッド ブロックの場合、ロックは同期ブラケットで設定されたオブジェクトです。
スレッドが同期コード ブロックにアクセスしようとすると、まずロックを取得し、終了するか例外をスローするときにロックを解放する必要があります。同期メソッドを作成するには、同期キーワードを使用します。
このキーワードによって変更されたメソッドは、オブジェクトの同期メソッドにアクセスするときに、同期メソッドと呼ばれます。これは、単にこのメソッドをロックするのではなく、オブジェクトがロックされていることを意味します。

このように、オブジェクトの同期されたメソッドがスレッドによって実行されると、他のスレッドはそのオブジェクトのどの同期されたメソッドにもアクセスできなくなります。同期メソッドは、その時点まで呼び出すことができます)。

静的同期メソッド呼び出しの状況:

オブジェクトの静的同期メソッドが呼び出されるとき、それは同期メソッドが配置されているオブジェクトではなく、同期メソッドが配置されているオブジェクトに対応するクラス オブジェクト。スレッドはこのクラスの他の静的同期メソッドを呼び出すことはできません。

結論: 静的同期メソッドを実行して、そのオブジェクトが配置されているオブジェクトをロックします。メソッドを見つけて、そのメソッドに対応する Class オブジェクトをロックする非静的同期メソッドを実行します。

以下は、メソッドが存在するオブジェクトに対応する Class オブジェクトをマルチスレッドで呼び出す例です。配置されたメソッドはロックされており、他のスレッドはメソッドが配置されているオブジェクトの他の静的同期メソッドを呼び出すことができません:

/**
 * 定义一个类,包含了线程类需要调用的方法
 */
class Compute1{
 //这时如果某个线程调用该方法,
 //将锁定synchronized方法所在对象对应的class对象,
 //而不是锁定synchronized方法所在对象
 public synchronized static void execute(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute1 " + i++);
  }
 }
 public synchronized static void execute2(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute2 " + i++);
  }
 }
}

メインメソッドでは、2 つのスレッドがそれぞれ同じものを呼び出します オブジェクトの 2 つの静的同期メソッド:

public static void main(String[] args) {
 Compute1 com = new Compute1();
 Thread thread1 = new Thread1(com);
 Thread thread2 = new Thread2(com);
 thread1.start();
 thread2.start();
}

static は 1 つだけメソッドは、実行が完了するまで一度に呼び出すことができます。

2.2. synchronized を使用して同期コード ブロックを作成します。

synchronized 同期コード ブロックを使用すると、オブジェクトがロックされ、オブジェクトが使用可能になります。同期効果:

/**
 * 定义一个类,包含了线程类需要调用的方法
 */
class Compute1{
 //通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块
 private Object object1 = new Object();
 public void execute(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute1 " + i++);
   }
  }
 
 }
 public synchronized void execute2(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute2 " + i++);
   }
  }
 }
}

同期された同期コード ブロックを使用して、同期メソッドを使用した場合と同じ効果を達成したい場合は、このリファレンスをロックできます:

synchronized(this){
 …
}

2.3. 同期メソッドと同期同期コード ブロックの違い:
同期されたコード ブロックはコード ブロックのみをロックし、コード ブロックの外側のコードには引き続きアクセスできます。

同期メソッドは、一定の時間に 1 つのスレッドのみが実行できる粗粒度の同時実行制御です。

同期された同期コード ブロックは、ブロック内のコードのみが同期され、他のスレッドから同時にアクセスできます。

Java マルチスレッド プログラミングにおけるスレッド同期方法の詳細な説明については、PHP 中国語 Web サイトに注目してください。


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