Java学習シリーズ(十五)Javaオブジェクト向けの細談スレッド、スレッド通信(下)


競合リソース(共有リソース):複数のスレッドが同時にアクセスし、オブジェクトを変更する必要がある場合は、そのオブジェクトが競合リソースです.複数のスレッドの「フリー競合」が共有リソースを変更することによる不安全な問題を回避するために.
スレッドの同期(Vector、Hashtableなどはスレッドが安全):スレッドの非同期化を解決するには2つの方法があります.
1)同期コードブロック(明示的な同期監視ロックが必要);2).同期メソッド(メソッドを使用する呼び出し元に相当し、メソッドがインスタンスメソッドの場合、thisが同期監視ロックに相当し、メソッドがクラスメソッドの場合、同期監視ロックとしてクラスに相当する).これらの実装メカニズムは完全に同じであり、スレッドが「同期監視ロック」によって監視されるコードに入る前に、スレッドはまず「同期監視ロック」を取得しなければならない.これにより、任意の時点で、1つのスレッドだけが「同期監視ロック」によって監視されるコードに入ることを保証することができる.プログラムロジックから、同期監視ロックとして「競合リソース」を選択します.例1-同期コードブロック(コードはすべていくつかの属性であるため、ここではクリップだけを抽出し、思想を把握すればよい):
//      ,synchronized              
		synchronized (account) {
			if (account.getBalance() > drawAmount) {
				System.out.println("    ,    :" + drawAmount);
				account.setBalance(account.getBalance() - drawAmount);
				System.out.println("     :" + account.getBalance());
			} else {
				System.out.println("    ,    !");
			}
		}

例2:同期監視ロックとしてthisを使用する同期方法.
public synchronized void draw(double drawAmount){
		if (getBalance() > drawAmount) {
			System.out.println("    ,    :" + drawAmount);
			setBalance(getBalance() - drawAmount);
			System.out.println("     :" + getBalance());
		} else {
			System.out.println("    ,    !");
		}
	}

スレッド同期のキー:同期モニタが監視するコードの前に、同期モニタをロックする必要があります.
[同期モニタ]へのロックはいつ解放されますか.1.同期コードブロックまたは同期メソッドの実行が完了しました.2.コードでbreak、return文がコードブロックから飛び出しました.3.同期コードブロックまたは同期メソッドの実行中に未取得の例外が発生した場合.4.同期モニタのwait()メソッドが呼び出されました.
【注意】sleep()、yield()を使用しても解放されません.
スレッド通信:1.制御を加えない場合、複数のスレッドが「自由」に同時実行されます.2.同期により、複数のスレッドが競合リソースに同時にアクセスする問題を解決できます.スレッドは安全で、必然的に性能を低下させます.3.スレッド間でより秩序正しく実行したい場合.
スレッドグループThreadGroupと未処理の例外:指定したスレッドグループにスレッドを入れるにはどうすればいいですか?--Threadインスタンスを作成すると、入力されたThreadGroupオブジェクトを使用して、指定したスレッドグループにスレッドを配置し、スレッドグループを使用してスレッド全体を管理できます.ThreadGroupは、setDaemon(boolean daemon)制御がスレッドグループ自体をバックグラウンドスレッドグループに設定し、含まれるスレッドをバックグラウンドスレッドに設定するのではなく、次の2つの方法を提供します.setMaxPriority(優先度):スレッドグループの既存のスレッドの優先度を設定しても影響を受けず、後で新しく追加したスレッドの優先度に影響を与えます.
スレッド異常の処理:JDK 1.5より前に、システムは自動的にそのオンラインスレッドグループのuncaughtException(Thread t,Throwable)方法をコールバックしてこの異常を修復する.JDK 1.5以降、スレッドはスレッドグループを必要とせずに「例外プロセッサ」を自分で設定できます.public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh):すべてのスレッドにデフォルトの例外プロセッサを設定します.public void setuUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh):現在のスレッドインスタンスに例外プロセッサを設定します.
列挙説明1(jdk 1.5より前):
public class ThreadExceptionTest implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "--->" + i
					/ (i - 20));
		}
	}

	public static void main(String[] args) {
		//        
		ThreadGroup tg = new ThreadGroup("mytg") {
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println(t.getName() + "     ,   :" + e.getMessage());
			}
		};
		ThreadExceptionTest test = new ThreadExceptionTest();
		new Thread(tg, test).start();
	}

}

列挙説明2(jdk 1.5以降):
public class ThreadExceptionTest implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + "--->" + i
					/ (i - 20));
		}
	}

	public static void main(String[] args) {
		//                
		Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println(t.getName() + "     ,   :" + e.getMessage());
			}
		});
		ThreadExceptionTest test = new ThreadExceptionTest();
		new Thread(test).start();
	}
}

スレッドプール(Pool):プールの本質は、「キャッシュ」技術です.オブジェクトをキャッシュするかどうかは、そのオブジェクトの作成コストによって決まります.Executors--スレッドプール、スレッドファクトリのツールクラスを作成します.ExecutorService:スレッドプールです.キャッシュの本質:時間をスワップするために空間(メモリ)を犠牲にします.スレッドオブジェクトの作成コストは比較的大きい(作成プロセスのコストよりずっと小さいが、通常のjavaオブジェクトに比べてThreadの作成コストは依然として大きい)ため、この問題を解決するためにスレッドプールを使用します.
プログラミング手順:1.ExecutorsのスタティックファクトリメソッドでExecutorServiceまたはScheduledExecutorService 2を作成します.ExecutorServiceのメソッドを呼び出してスレッドをコミットすればよい.3.スレッドプールを呼び出す.shutdownメソッドはスレッドプールを閉じます.
例1:
public class ThreadPoolTest implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ",i=" + i);
		}
	}

	public static void main(String[] args) {
		ExecutorService es = Executors.newFixedThreadPool(10);
		es.submit(new ThreadPoolTest());
		es.shutdownNow();//      
	}
}
例2:
public class ThreadPoolTest implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ",i=" + i);
		}
	}

	public static void main(String[] args) {
		ScheduledExecutorService es = Executors.newScheduledThreadPool(10);
		//   5s,    2s    run  
		es.scheduleAtFixedRate(new ThreadPoolTest(), 5, 2, TimeUnit.SECONDS);
	}
}