検索
ホームページJava&#&チュートリアルSynchronized in Java 同時プログラミング入門の学習ノート

1. Synchronized の基本的な使用法

Synchronized は、Java での同時実行の問題を解決するために最も一般的に使用される方法の 1 つであり、最も簡単な方法でもあります。 Synchronized には 3 つの主な機能があります: (1) スレッドが同期コードにアクセスする際に相互に排他的であることを保証する (2) 共有変数への変更が適時に確認できることを保証する (3) 並べ替えの問題を効果的に解決する。文法的に言えば、Synchronized には合計 3 つの使用法があります:

(1) 通常のメソッドを変更する

(2) 静的メソッドを変更する

(3) コードブロックを変更する

次に、いくつかのサンプルプログラムを通してこれを説明します。 (比較の便宜上、Synchronized の使用方法が異なることを除いて、3 つのコードは基本的に同じです)。

1. 同期なし:

コードセグメント 1:

package com.paddx.test.concurrent;
 
public class SynchronizedTest {
  public void method1(){
    System.out.println("Method 1 start");
    try {
      System.out.println("Method 1 execute");
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 1 end");
  }
 
  public void method2(){
    System.out.println("Method 2 start");
    try {
      System.out.println("Method 2 execute");
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 2 end");
  }
 
  public static void main(String[] args) {
    final SynchronizedTest test = new SynchronizedTest();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method1();
      }
    }).start();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method2();
      }
    }).start();
  }
}

スレッド 1 とスレッド 2 は同時に実行状態になるため、スレッド 2 はスレッドを完了します。この処理はスレッド 1 とスレッド 2 が同時に実行されます。

メソッド1 start
メソッド1execute
メソッド2 start
メソッド2execute
メソッド2 end
メソッド1 end

2. 通常のメソッドを同期します:

コードセグメント2:

package com.paddx.test.concurrent;
 
public class SynchronizedTest {
  public synchronized void method1(){
    System.out.println("Method 1 start");
    try {
      System.out.println("Method 1 execute");
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 1 end");
  }
 
  public synchronized void method2(){
    System.out.println("Method 2 start");
    try {
      System.out.println("Method 2 execute");
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 2 end");
  }
 
  public static void main(String[] args) {
    final SynchronizedTest test = new SynchronizedTest();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method1();
      }
    }).start();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method2();
      }
    }).start();
  }
}

実行結果は次のとおりです。コードに従ってください。 最初の段落を比較すると、スレッド 2 はメソッド 2 メソッドの実行を開始する前に、スレッド 1 のメソッド 1 の完了を待つ必要があることが明確にわかります。

メソッド1開始
メソッド1実行
メソッド1終了
メソッド2開始
メソッド2実行
メソッド2終了

3.静的メソッド(クラス)の同期

コードセグメント3:

package com.paddx.test.concurrent;
  
 public class SynchronizedTest {
   public static synchronized void method1(){
     System.out.println("Method 1 start");
     try {
       System.out.println("Method 1 execute");
       Thread.sleep(3000);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
     System.out.println("Method 1 end");
   }
  
   public static synchronized void method2(){
     System.out.println("Method 2 start");
     try {
       System.out.println("Method 2 execute");
       Thread.sleep(1000);
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
     System.out.println("Method 2 end");
   }
  
   public static void main(String[] args) {
     final SynchronizedTest test = new SynchronizedTest();
     final SynchronizedTest test2 = new SynchronizedTest();
  
     new Thread(new Runnable() {
       @Override
       public void run() {
         test.method1();
       }
     }).start();
  
     new Thread(new Runnable() {
       @Override
       public void run() {
         test2.method2();
       }
     }).start();
   }
 }

実行結果は以下の通りです。静的メソッドの同期は本質的にクラスの同期です (静的メソッドは本質的にクラスに属するメソッドであり、オブジェクトのメソッドではありません)。そのため、test と test2 が異なるオブジェクトに属していても、両方とも SynchronizedTest クラスのインスタンスに属します。 Method1 と Method2 は順次にのみ実行でき、同時に実行することはできません。

メソッド 1 開始
メソッド 1 実行
メソッド 1 終了
メソッド 2 開始
メソッド 2 実行
メソッド 2 終了

4. コードブロックの同期

コードセグメント 4:

package com.paddx.test.concurrent;
 
public class SynchronizedTest {
  public void method1(){
    System.out.println("Method 1 start");
    try {
      synchronized (this) {
        System.out.println("Method 1 execute");
        Thread.sleep(3000);
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 1 end");
  }
 
  public void method2(){
    System.out.println("Method 2 start");
    try {
      synchronized (this) {
        System.out.println("Method 2 execute");
        Thread.sleep(1000);
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("Method 2 end");
  }
 
  public static void main(String[] args) {
    final SynchronizedTest test = new SynchronizedTest();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method1();
      }
    }).start();
 
    new Thread(new Runnable() {
      @Override
      public void run() {
        test.method2();
      }
    }).start();
  }
}

実行結果は次のとおりです。スレッド 1 とスレッド 2 は対応するメソッドに入って実行を開始しましたが、スレッド 2 は同期ブロックに入る前にスレッド 1 の同期ブロックが完了するまで待つ必要があります。

方法 1 開始
方法 1 実行
方法 2 開始
方法 1 終了
方法 2 実行
方法 2 終了

2. 上記の実行結果についてまだ疑問がある場合は、心配しないでください。まずは同期の原理を理解しましょう。そうすれば、上記の疑問は一目瞭然です。まず、次のコードを逆コンパイルして、Synchronized がコード ブロックをどのように同期するかを見てみましょう:

package com.paddx.test.concurrent;
 
public class SynchronizedDemo {
  public void method() {
    synchronized (this) {
      System.out.println("Method 1 start");
    }
  }
}

逆コンパイル結果:

Java 并发编程学习笔记之Synchronized简介 これら 2 つの命令の役割については、JVM 仕様の説明を直接参照します:

monitorenter:

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.

この文章の一般的な意味は次のとおりです:

各オブジェクトにはモニター ロック (モニター) があります。モニターが占有されている場合、スレッドはモニターの所有権を取得しようとします:

1。 、スレッドはモニターに入り、エントリー番号を 1 に設定します。 、このスレッドはモニターの所有者です。

2. スレッドが既にモニターを占有していて再入する場合、モニターへのエントリー数は 1 つ増加します。

3. 他のスレッドが既にモニターを占有している場合、スレッドはブロック状態になります。モニターへのエントリー数が 0 になるまで、モニターの所有権を再度取得してみます。

monitorexit:

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

この部分の一般的な意味は次のとおりです:

monitorexit を実行するスレッドは、objectref に対応するモニターの所有者でなければなりません。

命令が実行されると、モニターのエントリー番号が 1 ずつ減分されます。1 減分した後にエントリー番号が 0 になった場合、スレッドはモニターを終了し、モニターの所有者ではなくなります。このモニターによってブロックされている他のスレッドは、このモニターの所有権を取得しようとする可能性があります。

これらの 2 つの段落の説明を通じて、Synchronized の基本的なセマンティクスはモニター オブジェクトを通じて完了することが明確に理解できるはずです。実際、wait/notify およびその他のメソッドもモニター オブジェクトに依存します。そのため、wait/notify などのメソッドのみを同期されたブロックまたはメソッドでのみ呼び出すことができ、それ以外の場合は java.lang.IllegalMonitorStateException がスローされます。

同期メソッドの逆コンパイル結果を見てみましょう:

ソースコード:

package com.paddx.test.concurrent;
 
public class SynchronizedMethod {
  public synchronized void method() {
    System.out.println("Hello World!");
  }
}

  从反编译的结果来看,方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。

三、运行结果解释

  有了对Synchronized原理的认识,再来看上面的程序就可以迎刃而解了。

1、代码段2结果:

  虽然method1和method2是不同的方法,但是这两个方法都进行了同步,并且是通过同一个对象去调用的,所以调用之前都需要先去竞争同一个对象上的锁(monitor),也就只能互斥的获取到锁,因此,method1和method2只能顺序的执行。

2、代码段3结果:

  虽然test和test2属于不同对象,但是test和test2属于同一个类的不同实例,由于method1和method2都属于静态同步方法,所以调用的时候需要获取同一个类上monitor(每个类只对应一个class对象),所以也只能顺序的执行。

3、代码段4结果:

  对于代码块的同步实质上需要获取Synchronized关键字后面括号中对象的monitor,由于这段代码中括号的内容都是this,而method1和method2又是通过同一的对象去调用的,所以进入同步块之前需要去竞争同一个对象上的锁,因此只能顺序执行同步块。

四 总结

  Synchronized是Java并发编程中最常用的用于保证线程安全的方式,其使用相对也比较简单。但是如果能够深入了解其原理,对监视器锁等底层知识有所了解,一方面可以帮助我们正确的使用Synchronized关键字,另一方面也能够帮助我们更好的理解并发编程机制,有助我们在不同的情况下选择更优的并发策略来完成任务。对平时遇到的各种并发问题,也能够从容的应对。


更多Java 并发编程学习笔记之Synchronized简介相关文章请关注PHP中文网!


声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?高度なJavaプロジェクト管理、自動化の構築、依存関係の解像度にMavenまたはGradleを使用するにはどうすればよいですか?Mar 17, 2025 pm 05:46 PM

この記事では、Javaプロジェクト管理、自動化の構築、依存関係の解像度にMavenとGradleを使用して、アプローチと最適化戦略を比較して説明します。

適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?適切なバージョン化と依存関係管理を備えたカスタムJavaライブラリ(JARファイル)を作成および使用するにはどうすればよいですか?Mar 17, 2025 pm 05:45 PM

この記事では、MavenやGradleなどのツールを使用して、適切なバージョン化と依存関係管理を使用して、カスタムJavaライブラリ(JARファイル)の作成と使用について説明します。

カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか?Mar 17, 2025 pm 05:44 PM

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPA(Java Persistence API)を使用するにはどうすればよいですか?Mar 17, 2025 pm 05:43 PM

この記事では、キャッシュや怠zyなロードなどの高度な機能を備えたオブジェクトリレーショナルマッピングにJPAを使用することについて説明します。潜在的な落とし穴を強調しながら、パフォーマンスを最適化するためのセットアップ、エンティティマッピング、およびベストプラクティスをカバーしています。[159文字]

Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか?Mar 17, 2025 pm 05:35 PM

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

See all articles

ホット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ヘンタイを無料で生成します。

ホットツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。