ホームページ Java &#&チュートリアル JavaでのSynchronizedの使用方法

JavaでのSynchronizedの使用方法

Dec 13, 2016 am 11:04 AM
synchronized

synchronized は Java のキーワードであり、同期ロックの一種です。変更するオブジェクトは次のとおりです:
1. コード ブロックを変更します。変更されたコード ブロックは、中括弧 {} で囲まれたコードであり、オブジェクトはこのコード ブロックを呼び出します。 ;
2. メソッドを変更します。変更されたメソッドは同期メソッドと呼ばれ、そのスコープはこのメソッドを呼び出すオブジェクトです。
3. 静的メソッドを変更します。静的メソッド全体とそれが作用するオブジェクトはすべてこのクラスのオブジェクトです
4. クラスを変更する場合、その作用範囲は同期後の括弧で囲まれた部分であり、作用する主なオブジェクトはすべてこのクラスのオブジェクトです。このクラス。

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

スレッドがオブジェクト内の synchronized (this) 同期コード ブロックにアクセスすると、そのオブジェクトにアクセスしようとしている他のスレッドはブロックされます。次の例を見てみましょう:

[Demo1]: 同期された

/**
 * 同步线程
 */class SyncThread implements Runnable {   private static int count;   public SyncThread() {
      count = 0;
   }   public  void run() {      synchronized(this) {         for (int i = 0; i < 5; i++) {            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }   public int getCount() {      return count;
   }
}
ログイン後にコピー

の使用法 SyncThread の呼び出し:

SyncThread syncThread = new SyncThread();
Thread thread1 = new Thread(syncThread, "SyncThread1");
Thread thread2 = new Thread(syncThread, "SyncThread2");
thread1.start();
thread2.start();
ログイン後にコピー

結果は次のようになります:

SyncThread1:0 
SyncThread1:1 
SyncThread1:2 
SyncThread1:3 
SyncThread1:4 
SyncThread2:5 
SyncThread2:6 
SyncThread2:7 
SyncThread2:8 
SyncThread2:9*
ログイン後にコピー

2 つの同時スレッド (thread1 と thread2) が同じオブジェクト (syncThread) にアクセスするとき同期されたコード ブロックが使用される場合、同時に実行できるのは 1 つのスレッドのみであり、もう 1 つのスレッドはブロックされ、現在のスレッドがコード ブロックの実行を完了するまでコード ブロックを実行する必要があります。同期されたコード ブロックの実行時に現在のオブジェクトがロックされるため、スレッド 1 とスレッド 2 は相互に排他的です。コード ブロックの実行後にのみオブジェクトのロックが解除され、次のスレッドがオブジェクトを実行してロックできるようになります。
SyncThread の呼び出しを少し変更してみましょう:

Thread thread1 = new Thread(new SyncThread(), "SyncThread1");
Thread thread2 = new Thread(new SyncThread(), "SyncThread2");
thread1.start();
thread2.start();
ログイン後にコピー

結果は次のとおりです:

SyncThread1:0 
SyncThread2:1 
SyncThread1:2 
SyncThread2:3 
SyncThread1:4 
SyncThread2:5 
SyncThread2:6 
SyncThread1:7 
SyncThread1:8 
SyncThread2:9
ログイン後にコピー

あるスレッドが同期されたコード ブロックを実行すると、他のスレッドがブロックされるという意味ではありませんでしたか?上記の例で thread1 と thread2 が同時に実行されるのはなぜですか?これは、synchronized はオブジェクトをロックするだけであり、各オブジェクトには 1 つのロック (ロック) だけが関連付けられており、上記のコードは次のコードと同等であるためです:

SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();
ログイン後にコピー
ログイン後にコピー

この時点で、2 つの SyncThread オブジェクト、syncThread1 と syncThread2 が作成されます。 Thread1 は syncThread1 オブジェクトの同期コード (run) を実行し、スレッド thread2 は syncThread2 オブジェクトの同期コード (run) を実行します。同期はオブジェクトをロックし、syncThread1 オブジェクトと syncThread2 オブジェクトをロックする 2 つのロックがあることがわかります。 、これら 2 つのロックは互いに干渉せず、相互排他を形成しないため、2 つのスレッドは同時に実行できます。

2. スレッドがオブジェクトの同期された (この) 同期コード ブロックにアクセスするとき、別のスレッドはオブジェクト内の非同期 (この) 同期されたコード ブロックにアクセスできます。
[Demo2]: 複数のスレッドが同期および非同期のコード ブロックにアクセスします

class Counter implements Runnable{
   private int count;   public Counter() {      count = 0;
   }   public void countAdd() {
      synchronized(this) {         for (int i = 0; i < 5; i ++) {            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }   //非synchronized代码块,未对count进行读写操作,所以可以不用synchronized
   public void printCount() {      for (int i = 0; i < 5; i ++) {         try {
            System.out.println(Thread.currentThread().getName() + " count:" + count);
            Thread.sleep(100);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }   public void run() {
      String threadName = Thread.currentThread().getName();      if (threadName.equals("A")) {
         countAdd();
      } else if (threadName.equals("B")) {
         printCount();
      }
   }
}
ログイン後にコピー

呼び出しコード:

Counter counter = new Counter();
Thread thread1 = new Thread(counter, "A");
Thread thread2 = new Thread(counter, "B");
thread1.start();
thread2.start();
ログイン後にコピー

結果は次のとおりです:

A:0 
B count:1 
A:1 
B count:2 
A:2 
B count:3 
A:3 
B count:4 
A:4 
B count:5
ログイン後にコピー

上記のコードでは、countAdd は同期され、printCount は非同期です。上記の結果から、スレッドがオブジェクトの同期コード ブロックにアクセスすると、他のスレッドはブロックされることなくオブジェクトの非同期コード ブロックにアクセスできることがわかります。

オブジェクトのロックを指定します

[Demo3]: オブジェクトのロックを指定します

/**
 * 银行账户类
 */class Account {
   String name;   float amount;   public Account(String name, float amount) {      this.name = name;      this.amount = amount;
   }   //存钱
   public  void deposit(float amt) {
      amount += amt;      try {
         Thread.sleep(100);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }   //取钱
   public  void withdraw(float amt) {
      amount -= amt;      try {
         Thread.sleep(100);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }   public float getBalance() {      return amount;
   }
}/**
 * 账户操作类
 */class AccountOperator implements Runnable{   private Account account;   public AccountOperator(Account account) {      this.account = account;
   }   public void run() {      synchronized (account) {
         account.deposit(500);
         account.withdraw(500);
         System.out.println(Thread.currentThread().getName() + ":" + account.getBalance());
      }
   }
}
ログイン後にコピー

呼び出しコード:

Account account = new Account("zhang san", 10000.0f);
AccountOperator accountOperator = new AccountOperator(account);final int THREAD_NUM = 5;
Thread threads[] = new Thread[THREAD_NUM];for (int i = 0; i < THREAD_NUM; i ++) {
   threads[i] = new Thread(accountOperator, "Thread" + i);
   threads[i].start();
}
ログイン後にコピー

結果は次のようになります:

Thread3:10000.0 
Thread2:10000.0 
Thread1:10000.0 
Thread4:10000.0 
Thread0:10000.0
ログイン後にコピー

AccountOperator クラスの run メソッドでは、synchronized adds を使用します。アカウントオブジェクトにロックします。このとき、スレッドがアカウント オブジェクトにアクセスすると、そのスレッドがアカウント オブジェクトにアクセスするまで、そのアカウント オブジェクトにアクセスしようとする他のスレッドはブロックされます。言い換えれば、ロックを取得した人は誰でも、そのロックが制御するコードを実行できます。
ロックとしてクリアなオ​​ブジェクトがある場合は、以下のような方法でプログラムを書くことができます。

public void method3(SomeObject obj)
{   //obj 锁定的对象
   synchronized(obj)
   {      // todo
   }
}
ログイン後にコピー

ロックとして明示的なオブジェクトがなく、コードの一部を同期したいだけの場合は、ロックとして機能する特別なオブジェクトを作成できます:

class Test implements Runnable{
   private byte[] lock = new byte[0];  // 特殊的instance变量
   public void method()
   {
      synchronized(lock) {         // todo 同步代码块
      }
   }   public void run() {

   }
}
ログイン後にコピー

説明: 長さ 0 のバイト配列オブジェクトは、どのオブジェクトよりも作成が経済的 - コンパイルされたバイトコードを見ると、長さ 0 の byte[] オブジェクトの生成に必要なオペコードは 3 つだけですが、Object lock = new Object() には 7 行のオペコードが必要です。

メソッドを変更する

同期化 メソッドの変更は非常に簡単で、メソッドの前に synchronized を追加するだけです。スコープが異なります。変更されたコード ブロックは中括弧で囲まれたスコープですが、変更されたメソッドのスコープは関数全体です。 [Demo1]の実行方法を以下の方法に変更しても同様の効果が得られます。

*[Demo4]: synchronized はメソッドを変更します

public synchronized void run() {   for (int i = 0; i < 5; i ++) {      try {
         System.out.println(Thread.currentThread().getName() + ":" + (count++));
         Thread.sleep(100);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }
}
ログイン後にコピー

Synchronized はメソッド全体に作用します。
メソッド 1 の記述:

public synchronized void method()
{
   // todo
}
ログイン後にコピー

メソッド 2 の記述:

public void method(){
   synchronized(this) {
      // todo
   }}
ログイン後にコピー

メソッド 1 の記述はメソッドを変更し、メソッド 2 の記述はコード ブロックを変更しますが、メソッド 1 の記述とメソッド 2 の記述は同等であり、どちらもメソッド全体のコンテンツをロックします。

在用synchronized修饰方法时要注意以下几点:
1. synchronized关键字不能继承。
虽然可以使用synchronized来定义方法,但synchronized并不属于方法定义的一部分,因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,而在子类中覆盖了这个方法,在子类中的这个方法默认情况下并不是同步的,而必须显式地在子类的这个方法中加上synchronized关键字才可以。当然,还可以在子类方法中调用父类中相应的方法,这样虽然子类中的方法不是同步的,但子类调用了父类的同步方法,因此,子类的方法也就相当于同步了。这两种方式的例子代码如下:
在子类方法中加上synchronized关键字

class Parent {
   public synchronized void method() { }
}class Child extends Parent {
   public synchronized void method() { }
}
ログイン後にコピー

在子类方法中调用父类的同步方法

class Parent {
   public synchronized void method() {   }
}class Child extends Parent {
   public void method() { super.method();   }
}
ログイン後にコピー

在定义接口方法时不能使用synchronized关键字。

构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。

修饰一个静态的方法

Synchronized也可修饰一个静态方法,用法如下:

public synchronized static void method() {
   // todo
}
ログイン後にコピー

我们知道静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象。我们对Demo1进行一些修改如下:

【Demo5】:synchronized修饰静态方法

/**
 * 同步线程
 */class SyncThread implements Runnable {   private static int count;   public SyncThread() {
      count = 0;
   }   public synchronized static void method() {      for (int i = 0; i < 5; i ++) {         try {
            System.out.println(Thread.currentThread().getName() + ":" + (count++));
            Thread.sleep(100);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }   public synchronized void run() {
      method();
   }
}
ログイン後にコピー

调用代码:

SyncThread syncThread1 = new SyncThread();
SyncThread syncThread2 = new SyncThread();
Thread thread1 = new Thread(syncThread1, "SyncThread1");
Thread thread2 = new Thread(syncThread2, "SyncThread2");
thread1.start();
thread2.start();
ログイン後にコピー
ログイン後にコピー

结果如下:

SyncThread1:0 
SyncThread1:1 
SyncThread1:2 
SyncThread1:3 
SyncThread1:4 
SyncThread2:5 
SyncThread2:6 
SyncThread2:7 
SyncThread2:8 
SyncThread2:9
ログイン後にコピー

syncThread1和syncThread2是SyncThread的两个对象,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以syncThread1和syncThread2相当于用了同一把锁。这与Demo1是不同的。

修饰一个类

Synchronized还可作用于一个类,用法如下:

class ClassName {
   public void method() {
      synchronized(ClassName.class) {
         // todo
      }
   }
}
ログイン後にコピー

我们把Demo5再作一些修改。
【Demo6】:修饰一个类

/**
 * 同步线程
 */
class SyncThread implements Runnable {
   private static int count;

   public SyncThread() {
      count = 0;
   }

   public static void method() {
      synchronized(SyncThread.class) {
         for (int i = 0; i < 5; i ++) {
            try {
               System.out.println(Thread.currentThread().getName() + ":" + (count++));
               Thread.sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }

   public synchronized void run() {
      method();
   }
}
ログイン後にコピー

其效果和【Demo5】是一样的,synchronized作用于一个类T时,是给这个类T加锁,T的所有对象用的是同一把锁。

总结:

A. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 
B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。 
C. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。


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

ホット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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Java での Synchronized の原理と使用シナリオ、および Callable インターフェイスの使用法と差異分析 Java での Synchronized の原理と使用シナリオ、および Callable インターフェイスの使用法と差異分析 Apr 21, 2023 am 08:04 AM

1. 基本機能 1. 楽観的ロックで開始し、ロック競合が多発する場合は悲観的ロックに変換する 2. 軽量なロック実装で開始し、長時間ロックを保持するとロックを解除する3. 軽量ロックを実装するときに最もよく使用されるスピン ロック戦略 4. 不公平なロックである 5. リエントラント ロックである 6. 読み取り/書き込みロックではない 2. JVMロック プロセスを同期します。 ロックは、ロックなし、バイアスされたロック、軽量ロック、および重量ロックの状態に分類されます。状況に応じて順次バージョンアップしていきます。偏ったロックは男主人公を鍵、女主人公をスレとするもので、このスレッドだけがこのロックを使用すれば、たとえ結婚証明書を取得しなくても男主人公と女主人公は永遠に幸せに暮らせる(高額回避) -コストオペレーション)しかし、女性のサポート役が登場します

Javaキーワード同期原理とロック状態の分析例 Javaキーワード同期原理とロック状態の分析例 May 11, 2023 pm 03:25 PM

1. Java におけるロックの概念 Spin ロック: スレッドがロックを取得するとき、そのロックが別のスレッドによって取得されている場合、スレッドはループで待機し、ロックが正常に取得できるかどうかを判断し続けます。ロックが取得されると、ロックはループを終了します。楽観的ロック: 競合がないことを前提として、データを変更する際に以前に取得したデータと不整合が見つかった場合、最新のデータを読み込み、変更を再試行します。悲観的ロック: 同時実行性の競合が発生することを想定し、すべてのデータ関連操作を同期し、データが読み取られた時点からロックを開始します。排他的ロック (書き込み): リソースに書き込みロックを追加します。スレッドはリソースを変更できますが、他のスレッドはリソースを再度ロックすることはできません (単一書き込み)。共有ロック (読み取り): リソースに読み取りロックを追加した後、読み取りのみ可能ですが変更はできません。他のスレッドは読み取りロックのみを追加でき、書き込みロック (複数) を追加できません。 S として参照

synchronized を使用して Java で同期メカニズムを実装するにはどうすればよいですか? synchronized を使用して Java で同期メカニズムを実装するにはどうすればよいですか? Apr 22, 2023 pm 02:46 PM

Java 1 での synchronized の使い方のまとめ。関数修飾子として synchronized を使用した場合のサンプルコードは次のようになります: Publicsynchronizedvoidmethod(){//….} これが同期メソッドですが、このときどのオブジェクトが同期ロックされているのでしょうか?彼がロックするのは、この同期されたメソッド オブジェクトを呼び出すことです。言い換えれば、オブジェクト P1 がこの同期メソッドを異なるスレッドで実行すると、同期効果を達成するために相互排他が形成されます。ただし、このオブジェクトが属するクラスが生成する別のオブジェクトP2は、synchronizedキーワードを付加してこのメ​​ソッドを任意に呼び出すことができる。上記のサンプルコードなど。

Java の 3 つの同期方法とその使用方法は何ですか? Java の 3 つの同期方法とその使用方法は何ですか? Apr 27, 2023 am 09:34 AM

1. 同期は最も一般的に使用される同期方法であり、これには主に 3 つの使用方法があることを説明します。 2. 例//一般的なクラス メソッドの同期 synchronizedpublidvoidinvoke(){}//クラスの静的メソッドの同期 synchronizedpublicstaticvoidinvoke(){}//コード ブロックの同期 synchronized(object){}これら 3 つのメソッドの違いは、同期されるオブジェクトが異なることです。通常のクラスはオブジェクト自体を同期し、静的メソッドはクラス自体を同期し、コード ブロックは括弧内のオブジェクトを同期します。 Javaにはどのようなコレクションがありますか?

Java 同期ロックのアップグレードの原理とプロセスは何ですか? Java 同期ロックのアップグレードの原理とプロセスは何ですか? Apr 19, 2023 pm 10:22 PM

ツールの準備 同期の原理について正式に説明する前に、まずスピン ロックについて話しましょう。スピン ロックは同期の最適化に大きな役割を果たすためです。スピン ロックを理解するには、まずアトミック性とは何かを理解する必要があります。いわゆるアトミック性とは、単に各操作が行われないか完了することを意味します。すべてを行うということは、操作中に中断できないことを意味します。たとえば、変数データに 1 を追加するには、次の 3 つのステップがあります: メモリからレジスタにロードする。データの値に 1 を加算します。結果をメモリに書き込みます。原子性とは、スレッドがインクリメント操作を実行しているときに、他のスレッドによって中断できないことを意味し、このスレッドがこれら 3 つのプロセスを完了した場合にのみ実行されます。

Java では、synchronized キーワードを使用するだけでなく、Lock を提供する必要があるのはなぜですか? Java では、synchronized キーワードを使用するだけでなく、Lock を提供する必要があるのはなぜですか? Apr 20, 2023 pm 05:01 PM

概要: synchronized キーワードは、1 つのスレッドのみが同期されたコード ブロックにアクセスできるようにするために Java で提供されています。 synchronized キーワードが提供されているのに、なぜ Lock インターフェースも Java SDK パッケージで提供されるのですか?これは不必要な車輪の再発明でしょうか?今日はこの問題について一緒に話し合います。 Java では synchronized キーワードが提供され、1 つのスレッドのみが同期されたコード ブロックにアクセスできるようにします。 synchronized キーワードが提供されているのに、なぜ Lock インターフェースも Java SDK パッケージで提供されるのですか?これは不必要な車輪の再発明でしょうか?今日は一緒にそれについて話し合いましょう

Java同期とは Java同期とは May 14, 2023 am 08:28 AM

Synchronized とは何ですか? Java 読者は synchronized キーワードに馴染みがありません。これはさまざまなミドルウェア ソース コードや JDK ソース コードで見ることができます。synchronized に詳しくない読者にとっては、synchronized キーワードは複数の言語で使用する必要があることだけを知っています。 -threading.synchronized によりスレッドの安全性を確保できます。これは、ミューテックス ロック (同時に 1 つのスレッドだけが実行でき、他のスレッドは待機します)、または悲観的ロック (同時に 1 つのスレッドだけが実行でき、他のスレッドは待機します) と呼ばれます。JVM 仮想マシンは、開発者は synchronized キーワードを使用するだけで済みます。使用する場合は、ロックのミューテックスとしてオブジェクトを使用する必要があります

Javaにおけるロックと同期の違いは何ですか Javaにおけるロックと同期の違いは何ですか Apr 17, 2023 pm 07:19 PM

1. 機能の観点から見ると、Lock と Synchronized はどちらもスレッド セーフティの問題を解決するために Java で使用されるツールです 2. 機能の観点から見ると、Synchronized は Java の同期キーワードであり、Lock は J.U.C パッケージで提供されるインターフェイスです, そしてこのインターフェイスには、ReentrantLock などの再入可能ロックの実装を含む、多くの実装クラスがあります。Synchronized は 2 つの方法でロックの強度を制御できます。1 つはメソッド レベルで synchronized キーワードを変更すること、もう 1 つはメソッド レベルで synchronized キーワードを変更することですコード ブロック上で使用できます。同期されたロック オブジェクトのライフ サイクルは、ロックのスコープを制御するために使用されます。ロック オブジェクトは静的オブジェクトまたはクラス ペアです。

See all articles