Javaでは、キーワード同期を使用して、スレッド同期制御に使用して、主要なリソースへの順次アクセスを実現し、マルチスレッドの同時実行によって引き起こされるデータの矛盾を回避できます。同期の原理は、オブジェクトモニター(ロック)です。モニターを取得するスレッドのみが実行され続けることができます。そうしないと、スレッドはモニターの取得を待ちます。 Javaの各オブジェクトまたはクラスには、ロックが関連付けられています。オブジェクトの場合、このオブジェクトのインスタンス変数を監視します。クラスの場合、クラス変数を監視します(クラス自体はクラスクラスのオブジェクトであるため、クラスに関連付けられているロックもオブジェクトロックです)。同期されたキーワードを使用するには、同期されたメソッドと同期ブロックを使用するには、2つの方法があります。両方の監視領域は、導入されたオブジェクトに関連付けられています。この監視領域に到達すると、JVMは参照オブジェクトをロックし、出発すると参照オブジェクトのロックがリリースされます(例外の出口があるときにJVMがロックを解放します)。オブジェクトロックは、JVMの内部メカニズムです。同期方法または同期ブロックを記述するだけです。監視エリアを操作すると、JVMはロックを自動的に取得またはリリースします。
例1
まず最初の例を見てみましょう。 Javaでは、同じオブジェクトの重要な領域が1つだけで、同時にアクセスできるようになります(すべての非静的同期方法):
パッケージの並行性; public class main8 {public static void main(string [] args){accountアカウント= new Account(); account.setbalance(1000); Company Company = New Company(アカウント);スレッドcompanythread = newスレッド(会社);銀行銀行=新しい銀行(アカウント);スレッドbankthread = newスレッド(銀行); System.out.printf( "account:initial Balance:%f/n"、account.getbalance()); companythread.start(); bankthread.start(); try {// join()メソッドこれらの2つのスレッドがcompanythread.join()を完了するのを待ちます。 bankthread.join(); System.out.printf( "アカウント:最終残高:%f/n"、account.getbalance()); } catch(arturnedexception e){e.printstacktrace(); }}} /*account*/classアカウント{プライベートダブルバランス; /*バランスのバランスに入るデータを追加*/ public同期void addAmount(double bomut){double tmp = balance; try {thread.sleep(10); } catch(arturnedexception e){e.printstacktrace(); } tmp +=額;バランス= TMP; } /*バランスバランスから着信データを差し引きます* / public同期ボイドsubtractAmount(double bomut){double tmp = balance; try {thread.sleep(10); } catch(arturnedexception e){e.printstacktrace(); } tmp - =額;バランス= TMP; } public double getBalance(){return balance; } public void setbalance(double balance){this.balance = balance; }} /*bank*/class銀行実装runnable {privateアカウントアカウント;パブリックバンク(アカウントアカウント){this.account = account; } @Override public void run(){for(int i = 0; i <100; i ++){account.subtractamount(1000); }}} /*Company*/class Companyはrunnable {privateアカウントアカウント;公開会社(アカウントアカウント){this.account = account; } @Override public void run(){for(int i = 0; i <100; i ++){account.addamount(1000); }}}銀行口座のシミュレーションアプリケーションを開発し、バランスを補充して控除できるようになりました。このプログラムは、AddAmount()メソッドを100回呼び出し、毎回1,000を預けてアカウントを充電します。次に、SubtractAmount()メソッドを100回呼び出し、毎回1,000を差し引くことにより、アカウントの残高を差し引きます。アカウントの最終的な残高は初期残高に等しいと予想し、同期されたキーワードを介してそれを実装します。
共有データの同時アクセスの問題を表示する場合は、AddAmount()およびSubtractAmount()メソッド宣言の同期キーワードを削除するだけです。同期されたキーワードがなければ、印刷されたバランス値は一貫していません。このプログラムを複数回実行すると、異なる結果が得られます。 JVMはスレッドの実行順序を保証しないため、スレッドが実行されるたびに、スレッドは異なる注文でアカウントの残高を読み取り、変更するため、最終結果は異なります。
オブジェクトのメソッドは、同期されたキーワードを使用して宣言され、1つのスレッドでのみアクセスできます。スレッドAが同期メソッドSyncMethoda()を実行している場合、Thread Bはこのオブジェクトの他の同期メソッドSyncMethodb()を実行する必要があります。スレッドBは、スレッドAがアクセスを完了するまでブロックされます。ただし、スレッドBが同じクラスの異なるオブジェクトにアクセスすると、どちらのスレッドもブロックされません。
例2
同じオブジェクトの静的同期メソッドと非静的同期メソッドに同時に複数のスレッドでアクセスできるという問題を示します。それを確認します。
パッケージの並行性; public class main8 {public static void main(string [] args){accountアカウント= new Account(); account.setbalance(1000); Company Company = New Company(アカウント);スレッドcompanythread = newスレッド(会社);銀行銀行=新しい銀行(アカウント);スレッドbankthread = newスレッド(銀行); System.out.printf( "account:initial Balance:%f/n"、account.getbalance()); companythread.start(); bankthread.start(); try {// join()メソッドこれらの2つのスレッドがcompanythread.join()を完了するのを待ちます。 bankthread.join(); System.out.printf( "アカウント:最終残高:%f/n"、account.getbalance()); } catch(arturnedexception e){e.printstacktrace(); }}} /*account*/classアカウント{/*ここで静的変数に変更*/private static double balance = 0; /*バランスバランスに着信データを追加するには、静的で修正されていることに注意してください*/ public static同期void addAmount(double bomut){double tmp = balance; try {thread.sleep(10); } catch(arturnedexception e){e.printstacktrace(); } tmp +=額;バランス= TMP; } /*バランスバランスから着信データを差し引きます* / public同期void subtractAmount(double bomut){double tmp = balance; try {thread.sleep(10); } catch(arturnedexception e){e.printstacktrace(); } tmp - =額;バランス= TMP; } public double getBalance(){return balance; } public void setbalance(double balance){this.balance = balance; }} /*bank*/class銀行実装runnable {privateアカウントアカウント;パブリックバンク(アカウントアカウント){this.account = account; } @Override public void run(){for(int i = 0; i <100; i ++){account.subtractamount(1000); }}} /*Company*/class Companyはrunnable {privateアカウントアカウント;公開会社(アカウントアカウント){this.account = account; } @Override public void run(){for(int i = 0; i <100; i ++){account.addamount(1000); }}}静的キーワードを追加して、前の例でバランスを変更するだけで、addAmount()メソッドは静的キーワードを変更することもできます。実行結果を自分でテストでき、各実行結果は異なります!
いくつかの概要: