(3)従来のスレッド反発技術synchronizedの古典的解析.【スレッド同期】追加【内部クラスと外部クラス】

9302 ワード

(1)まず振り返る:内部クラスと外部クラス
クリックしてリンクを開く
(2)スレッド同期(このテキストは参考になる)複数のスレッドが同じデータにアクセスすると、スレッドセキュリティの問題が発生しやすい.この場合、スレッドでCaseを同期する必要があります:銀行のお金を引き出す問題、以下のステップがあります:A、ユーザーが口座、パスワードを入力して、システムが登録に成功したかどうかを判断しますB、ユーザーがお金を引き出す金額Cを入力して、システムはお金を引き出す金額が既存の金額Dより大きいかどうかを判断して、もし金額がお金を引き出す金額より大きいならば、成功して、それ以外のプロンプトが残高より小さい場合、2人が同時に1つの口座から金を引き出すのをシミュレートすると、マルチスレッド操作に問題が発生します.この場合、同期が必要です.同期コードブロック:synchronized(object){//同期コード}Javaマルチスレッドはメソッド同期をサポートし、メソッド同期はsynchronizedでメソッドを修飾するだけでよいので、このメソッドが同期メソッドである.同期メソッドでは、指定された同期モニタを表示する必要はありません.同期メソッドモニタは、それ自体this同期メソッドです.public synchronized void editByThread()/doSomething}同期メソッドを使用する必要があるクラスには、A、このクラスのオブジェクトが複数のスレッドでBにアクセスできるという特徴があります.各スレッド呼び出しオブジェクトの任意は正常に終了し、正常結果C、各スレッド呼び出しオブジェクトの任意のメソッドに戻った後、このオブジェクトステータスは、オブジェクトステータスが変更できないため、合理的な状態を維持します.このオブジェクトステータスは常にスレッドセキュリティです.可変クラスオブジェクトは、スレッドセキュリティを保証するために追加の方法が必要です.たとえばAccountは可変クラスであり、moneyは可変であり、2つのスレッドが同時にmoneyを変更すると、プログラムに異常やエラーが発生します.Accountをスレッドセキュリティに設定するには、synchronizedキーワードを同期する必要があります.次の方法はsynchronized同期キーワードで修飾され、この方法は同期方法である.これにより、このメソッドにアクセスできるスレッドは1つしかありません.現在のスレッドがこのメソッドを呼び出すと、このメソッドはロックされた状態であり、同期モニタはthisです.このメソッドは、このメソッドの変更が完了した場合にのみ、他のスレッドが呼び出されます.これにより,スレッドの安全を保証し,マルチスレッドが同時に金を引き出す安全問題を処理することができる.public synchronized void drawMoney(double money){//お金を取る操作}注意:synchronizedはメソッド、コードブロックを修飾することができるが、属性を修飾できず、メソッド可変クラスを構築するスレッドセキュリティは、プログラムの実行効率を低下させる代わりに、スレッドセキュリティによる負の影響を低減するために、スレッドセキュリティクラスのすべてのメソッドに同期モードを使用しないで、競合するリソース(共有リソース)を変更するメソッドのみを同期するポリシーを使用できます.B、可変クラスに2つの実行環境がある場合:単一スレッド環境とマルチスレッド環境がある場合、この可変に2種類のバージョンを提供する.スレッドセキュリティと非スレッドセキュリティのバージョン.単一スレッドの下で非スレッドセキュリティを採用し、運行効率を高め、性能を保証し、マルチスレッド環境の下でスレッドセキュリティを採用する制御セキュリティの問題.同期モニタのロックを解除するスレッドが同期コードブロック、同期方法に入る前に、同期モニタのロックを取得する必要があります.同期モニタのロックはいつ解放されますか?プログラムが表示できない解放同期モニタに対するロック、スレッドは以下の方法でロックを解除することができる:A、スレッドの同期方法、同期コードライブラリの実行が終了すると、同期モニタBを解放することができ、スレッドが同期コードライブラリ、方法の中でbreak、returnがコードの実行を終了することに遭遇すると、C、スレッドが同期コードライブラリ、同期メソッドで未処理のError、Exceptionに遭遇すると、そのコードが終了しても同期モニタDを解放することができ、スレッドが同期コードライブラリ、同期メソッドでは、プログラムが同期モニタオブジェクトのwaitメソッドを実行し、メソッドが一時停止する、同期モニタを解放する次の場合、同期モニタは解放されません:A、スレッドが同期コードライブラリ、同期方法を実行する時、プログラムはThreadを呼び出しました.sleep()/Thread.yield()メソッドは、現在のプログラムを一時停止します.現在のプログラムは同期モニタBを解放しません.スレッドが同期コードライブラリ、同期メソッドを実行している間に、他のスレッドがスレッドを呼び出したsuspendメソッドは、同期モニタを解放しません.注意suspend、resumeの使用は避けてください
***
package com.itm.thread;

/*******************
 * 
 *           new         :                ,
 * 
 *    :                      。
 * 
 *                         ,    。
 * 
 * main       ,            ,         ,
 *                 ,         。
 * 
 *              ,             ,               。
 * 
 * (1)              final 。
 * 
 * 	                       。                          。
 * 
 * 
 * 
 * @author wang.dm
 * 
 */
public class TraditionalThreadSynchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
  				final Outputer outputer = new Outputer();
  
 				new Thread(new Runnable(){
		 				@Override 
		 				public void run() { 
		 				
		 					while(true){ 
		 						try { 
		 								Thread.sleep(1000);
		 							}catch (InterruptedException e) { 
		 								e.printStackTrace(); 
		 						}
		 						outputer.output("zhangxiaoxiang"); 
 					
 					} 
 				} 
	}).start();
		 			
		 
	}
	

	class Outputer {
		String xxx="";
		public void output(String name) {
			int len = name.length();
			
			synchronized(name){
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
			}
		}
	}

}

上のコードは間違っています.解決策:No.enclosing instance of type TraditionalThreadSynchronized is accessible.Must qualify the allocation with an enclosing instance of type TraditionalThreadSynchronized (e.g. x.new A() where x   is an instance of TraditionalThreadSynchronized). メソッドが呼び出されるときは、あるオブジェクトのメソッドに違いありません.彼は静的メソッドではなく、外部クラスのオブジェクトを作成したに違いありません.このメソッドが実行されるときは、必ずオブジェクトがあります.new Outputer()//こいつは必ず外部クラス、つまり誰がinit()メソッドを呼び出したのかを探さなければならない.
public class TraditionalThreadSynchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		 new TraditionalThreadSynchronized().init();
	}
	//                      ,         ,            ,
	//          ,       ,
	private void init(){
		final Outputer outputer = new Outputer();//             ,         init()  。
		  
			new Thread(new Runnable(){
 				@Override 
 				 public void run() { 
 				
 					while(true){ 
 						try { 
 								Thread.sleep(1000);
 							}catch (InterruptedException e) { 
 								e.printStackTrace(); 
 						}
 						outputer.output("zhangxiaoxiang"); 
				
 					} 
 				} 
			}).start();
			
			new Thread(new Runnable(){
 				@Override 
 				 public void run() { 
 				
 					while(true){ 
 						try { 
 								Thread.sleep(1000);
 							}catch (InterruptedException e) { 
 								e.printStackTrace(); 
 						}
 						outputer.output("lihuoming"); 
				
 					} 
 				} 
			}).start();
	}

	class Outputer {
		String xxx="";
		public void output(String name) {
			int len = name.length();
			
			synchronized(name){
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
			}
		}
	}

}

上のコードは、中間コードが乱されている、つまりマルチスレッドが好む問題です.一つのことが終わらないと、もう一つの事件が発生します.この問題を防ぐために、同期技術を使っています.for (int i = 0; i < len; i++) { System.out.print(name.charAt(i)); } System.out.println();//この文は改行です.このコードは原子性を実現しなければならない.つまり、ある県城が私を実行しに来たとき、他の県城は私を実行することができませんでした.トイレの穴のように、ガツンとしたsynchronized(name){//効果がなく、反発は必ず同じオブジェクトにしなければならない.for(int i=0;iclass Outputer { String xxx=""; public void output(String name) { int len = name.length(); synchronized(xxx){ for (int i = 0; i < len; i++) { System.out.print(name.charAt(i)); } System.out.println();// 。 } } }
変更する場合:new Outputer().output("lihuoming");問題があります.注意:同じオブジェクトを必ず使用してください.しかし、xxxはthisキーワードで代用することができます.そうしないと、これ以上はありません.2,もし私がoutput全体の方法のコードを保護するならば、どうします:それではこの方法の中でsynchronizedというキーワードを使います.次のコードも問題がなく、保護されている地域は違いますが、同じオブジェクトです.
package com.itm.thread;

/*******************
 * 
 *           new         :                ,
 * 
 *    :                      。
 * 
 *                         ,    。
 * 
 * main       ,            ,         ,
 *                 ,         。
 * 
 *              ,             ,               。
 * 
 * (1)              final 。
 * 
 * 	                       。                          。
 * 
 * 
 * 
 * @author wang.dm
 * 
 */
public class TraditionalThreadSynchronized {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		 new TraditionalThreadSynchronized().init();
	}
	//                      ,         ,            ,
	//          ,       ,
	private void init(){
		final Outputer outputer = new Outputer();//             ,         init()  。
		  
			new Thread(new Runnable(){
 				@Override 
 				 public void run() { 
 				
 					while(true){ 
 						try { 
 								Thread.sleep(1000);
 							}catch (InterruptedException e) { 
 								e.printStackTrace(); 
 						}
 						outputer.output("zhangxiaoxiang"); 
				
 					} 
 				} 
			}).start();
			
			new Thread(new Runnable(){
 				@Override 
 				 public void run() { 
 				
 					while(true){ 
 						try { 
 								Thread.sleep(1000);
 							}catch (InterruptedException e) { 
 								e.printStackTrace(); 
 						}
 						outputer.output2("lihuoming");
 						
				
 					} 
 				} 
			}).start();
	}

	class Outputer {
		public void output(String name) {
			int len = name.length();
			synchronized(this){//      ,            。
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
			}
		}
		
		public synchronized void output2(String name) {
			int len = name.length();
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
		}
	}
	
	

}

3,次のコードは:方法1,2はそれぞれ方法3と同期できますか??
static class Outputer {
		public void output(String name) {
			int len = name.length();
			synchronized(this){//      ,            。
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
			}
		}
		
		public synchronized void output2(String name) {
			int len = name.length();
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
		}
		
		public static synchronized void output3(String name) { //            ,  :      ,         static 。
			int len = name.length();
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();//       。
		}

結果:同期不可!!!メソッド1とメソッド3は同期していません.クラスのバイトコードはメモリにも対像です.静的メソッドが実行されるときはインスタンスオブジェクトを作成する必要はありません.バイトコードオブジェクトしかありません.同期させるには、メソッド1もバイトコードを使用しなければなりません.thisは、public void output(String name){int len=name.length();synchronized(Outputer.class){//効果がなく、反発は必ず同じオブジェクトにしなければならない.for(int i=0;i