[Java]ThreadとRunnable

#ステップ1,チケット販売を仮定のプログラム
####1.1 Mythread 作成
####1.2 main関数から起動する
#### 以下はサンプル


	class Mythread extends Thread {
	
		private int ticket = 5;
		@Override
		public void run() {
			for(int i =0 ; i<10 ; i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO 自動生成された catch ブロック
					e.printStackTrace();
				}
				if(ticket > 0 ) {
					ticket--;
					L.d("残チケット枚数は"+ticket+"枚");
				}
			}
		}
	}
	
	public class ThreadSample {
	
		public static void main(String[] args) {
			Mythread mythread = new Mythread();
			L.d("チケット販売開始");
			mythread.start();
		}
	}


結果：
ThreadSample#main:34   thread name:main   thread id:1   gentest ::チケット販売開始
Mythread#run:24   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は4枚
Mythread#run:24   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は3枚
Mythread#run:24   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は2枚
Mythread#run:24   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は1枚
Mythread#run:24   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は0枚


#ステップ2,チケット販売完了後の報告（コールバック）追加
####2.1 interface 作成
####2.2 mainクラスにてinterface の実現
####2.3 Mythreadのコンストラクタ追加
####2.4 Mythreadのrunにコールバック追加
#### 以下はサンプル

	interface MyTaskResult {
		void ticketSoldout();
		void ticketRemain();
	}

	class Mythread extends Thread {
		private MyTaskResult myTaskResult;
		public Mythread (MyTaskResult myTaskResult) {
			this.myTaskResult = myTaskResult;
		}

		private int ticket = 5;
		@Override
		public void run() {
			for(int i =0 ; i<10 ; i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO 自動生成された catch ブロック
					e.printStackTrace();
				}
				if(ticket > 0 ) {
					ticket--;
					L.d("残チケット枚数は"+ticket+"枚");
				}
			}
			if(ticket>0) {
				myTaskResult.ticketRemain();
			}else {
				myTaskResult.ticketSoldout();
			}
		}
	}

	public class ThreadSample {

		public static void main(String[] args) {
			Mythread mythread = new Mythread(myTaskResult);
			L.d("チケット販売開始");
			mythread.start();
		}
		static MyTaskResult myTaskResult = new MyTaskResult() {

			@Override
			public void ticketSoldout() {
				L.d("お疲れ様です。");
			}

			@Override
			public void ticketRemain() {
				L.d("終わっていないの？");
			}
		};
	}

結果は

ThreadSample#main:43   thread name:main   thread id:1   gentest ::チケット販売開始
Mythread#run:28   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は4枚
Mythread#run:28   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は3枚
Mythread#run:28   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は2枚
Mythread#run:28   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は1枚
Mythread#run:28   thread name:Thread-0   thread id:11   gentest ::残チケット枚数は0枚
ThreadSample$1#ticketSoldout:50   thread name:Thread-0   thread id:11   gentest ::お疲れ様です。

#ステップ３、多数券売機でチケットを販売する
####3.1 Runnable追加（TicketBox ）
####3.2 Thread の数追加、Thread 名追加（代理１，２，３）
#### 以下はサンプル


	interface MyTaskResult {
		void ticketSoldout(String threadName);
		void ticketRemain(String threadName);
	}

	class TicketBox implements Runnable {
		private int ticket = 5;
		@Override
		public void run() {
			for(int i =0 ; i<10 ; i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO 自動生成された catch ブロック
					e.printStackTrace();
				}
				if(ticket > 0 ) {
					ticket--;
					L.d("残チケット枚数は"+ticket+"枚");
				}
			}
			L.d("完了　チケット:"+ticket);
		}
	}

	class Mythread extends Thread {
		private MyTaskResult myTaskResult;
		public Mythread (Runnable r, MyTaskResult myTaskResult,String threadName) {
			super(r);
			this.myTaskResult = myTaskResult;
			setName(threadName);
		}

		private int ticket = 5;
		@Override
		public void run() {
			super.run();
		}
	}

	public class ThreadSample {

		public static void main(String[] args) {
			TicketBox ticketBox = new TicketBox();
			Mythread mythread1 = new Mythread(ticketBox,myTaskResult,"代理１");
			Mythread mythread2 = new Mythread(ticketBox,myTaskResult,"代理２");
			Mythread mythread3 = new Mythread(ticketBox,myTaskResult,"代理３");
			L.d("チケット販売開始");
			mythread1.start();
			mythread2.start();
			mythread3.start();
		}
		static MyTaskResult myTaskResult = new MyTaskResult() {

			@Override
			public void ticketSoldout(String threadName) {
				L.d("お疲れ様です。"+threadName);
			}

			@Override
			public void ticketRemain(String threadName) {
				L.d("終わっていないの？"+threadName);
			}
		};
	}

結果

ThreadSample#main:52   thread name:main   thread id:1   gentest ::チケット販売開始
TicketBox#run:23   thread name:代理２   thread id:12   gentest ::残チケット枚数は3枚
TicketBox#run:23   thread name:代理１   thread id:11   gentest ::残チケット枚数は3枚
TicketBox#run:23   thread name:代理３   thread id:13   gentest ::残チケット枚数は3枚
TicketBox#run:23   thread name:代理１   thread id:11   gentest ::残チケット枚数は2枚
TicketBox#run:23   thread name:代理２   thread id:12   gentest ::残チケット枚数は1枚
TicketBox#run:23   thread name:代理３   thread id:13   gentest ::残チケット枚数は0枚
TicketBox#run:26   thread name:代理２   thread id:12   gentest ::完了　残チケット:0
TicketBox#run:26   thread name:代理３   thread id:13   gentest ::完了　残チケット:0
TicketBox#run:26   thread name:代理１   thread id:11   gentest ::完了　残チケット:0

問題点：
１、チケット５枚に対して、６回売ってしまった。（同期処理必要）
２、各代理は何枚発売したを統計していない

#ステップ４ 同期処理

	class TicketBox implements Runnable {
		private int ticket = 5;
		@Override
		public void run() {
			for(int i =0 ; i<10 ; i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO 自動生成された catch ブロック
					e.printStackTrace();
				}
				saleTicket();
			}
			L.d("完了　残チケット:"+ticket);
		}
		private synchronized void saleTicket() {
			if(ticket > 0 ) {
				ticket--;
				L.d("残チケット枚数は"+ticket+"枚");
			}
		}
	}

結果

ThreadSample#main:55   thread name:main   thread id:1   gentest ::チケット販売開始
TicketBox#saleTicket:28   thread name:代理２   thread id:12   gentest ::残チケット枚数は4枚
TicketBox#saleTicket:28   thread name:代理３   thread id:13   gentest ::残チケット枚数は3枚
TicketBox#saleTicket:28   thread name:代理１   thread id:11   gentest ::残チケット枚数は2枚
TicketBox#saleTicket:28   thread name:代理２   thread id:12   gentest ::残チケット枚数は1枚
TicketBox#saleTicket:28   thread name:代理１   thread id:11   gentest ::残チケット枚数は0枚
TicketBox#run:23   thread name:代理２   thread id:12   gentest ::完了　残チケット:0
TicketBox#run:23   thread name:代理３   thread id:13   gentest ::完了　残チケット:0
TicketBox#run:23   thread name:代理１   thread id:11   gentest ::完了　残チケット:0

#ステップ５ 販売結果まとめ

[github参考してください](https://github.com/YanHengGo/java/tree/master/05_thread_rannable)

結果

ThreadSample#main:85   thread name:main   thread id:1   gentest ::チケット販売開始
TicketBox#saleTicket:52   thread name:代理2   thread id:12   gentest ::残チケット枚数は4枚
TicketBox#saleTicket:52   thread name:代理1   thread id:11   gentest ::残チケット枚数は3枚
TicketBox#saleTicket:52   thread name:代理3   thread id:13   gentest ::残チケット枚数は2枚
TicketBox#saleTicket:52   thread name:代理1   thread id:11   gentest ::残チケット枚数は1枚
TicketBox#saleTicket:52   thread name:代理2   thread id:12   gentest ::残チケット枚数は0枚
ThreadSample$1#taskDone:95   thread name:代理1   thread id:11   gentest ::お疲れ様です。代理1
ThreadSample$1#taskDone:95   thread name:代理2   thread id:12   gentest ::お疲れ様です。代理2
ThreadSample$1#taskDone:95   thread name:代理3   thread id:13   gentest ::お疲れ様です。代理3
ThreadSample$1#taskDone:100   thread name:代理3   thread id:13   gentest ::----------------全部完了　報告----------------------------
ThreadSample$2#sendResult:108   thread name:代理3   thread id:13   gentest ::全チケット数は：5
ThreadSample$2#sendResult:109   thread name:代理3   thread id:13   gentest ::残チケットは：0
ThreadSample$2#sendResult:110   thread name:代理3   thread id:13   gentest ::代理1販売結果:2
ThreadSample$2#sendResult:111   thread name:代理3   thread id:13   gentest ::代理2販売結果:2
ThreadSample$2#sendResult:112   thread name:代理3   thread id:13   gentest ::代理3販売結果:1