ICT関連の学習備忘録

ICTの学習をアウトプットするワークブックサイト

ICT関連の学習備忘録

2019/10/01:スレッドによる同時処理

スレッドを起動する(thread)

コード上の複数の箇所の処理が同時に行われるような
仕組みをスレッド(thread)と呼び、コード上で処理の流れを増やすことを
スレッドを起動するという。

スレッドを起動するためにはクラスライブラリのThreadクラス(java.langパッケージ)
を拡張したクラスを作成することが必要で、Threadクラスを拡張したクラスには
そのなかにrun()メソッドを定義し、このメソッドに処理を記述しておくと
その処理が、これまでとは異なる処理の流れのスタート地点になります。
class Car extends Thread	//CarクラスはThreadクラスを継承(スレッド処理する為)
{	//フィールド
   private String name;
	//コンストラクタ
   public Car(String nm) 
   {
      name = nm;
   }
	//メソッド
	//run()メソッドはスレッド起動時に実行するメソッド
	//Threadクラスよりオーバーライドしたもの
   public void run()
   {
      for(int i=0; i<1000; i++){
      	try{
      	sleep(5);
         System.out.println(name + "の処理をしています。");
      	}catch(InterruptedException e){}
      }
   }
}
class Sample1
{
   public static void main(String[] args)  throws InterruptedException
   {	//Car型オブジェクトを生成
      Car car1 = new Car("1号車");
      car1.start();	//car1オブジェクトのスレッドをスタート(main()とrun()並行処理開始)
   					//start()メソッドはThreadクラスから継承したメソッド。
      for(int i=0; i<1000; i++){
		car1.sleep(5);
         System.out.println("main()の処理をしています。");

      } 
   }
}

#実行結果
C:\YJSample\15>java Sample1
main()の処理をしています。
1号車の処理をしています。
2号車の処理をしています。
1号車の処理をしています。
2号車の処理をしています。
main()の処理をしています。
1号車の処理をしています。
2号車の処理をしています。
main()の処理をしています。
・
・
・

スレッドの一時停止(sleep)

sleep()メソッドというものを使うことで、起動したスレッドを
一時停止することができる。
利用する際にはtry~catchでメソッドから送出される可能性のある
例外を記述しないとコンパイルが通らない。
(略)
    try{

        Thread.sleep(1000);	    //1秒ごとに処理(1000ms)
        System.out.println("main()の処理をしています。");

     }
     catch(InterruptedException e){}
(略)

スレッドの終了を待つ

別のスレッドの終了を待って、自分の処理を再開する仕組みを
利用するにはjoin()メソッドを使います。
class Car extends Thread
{
   private String name;

   public Car(String nm)
   {
      name = nm;
   }
   public void run()
   {
      for(int i=0; i<5; i++){

         System.out.println(name + "の処理をしています。");

      } 
   }
}

class Sample5
{
   public static void main(String[] args)
   {
      Car car1 = new Car("1号車");
      car1.start();

      try{

         car1.join();	//car1.start()->car1.run()スレッドの終了待ち

      }
      //jjoin()メソッドから送出される可能性のある例外
      catch(InterruptedException e){}
   	//try内のcar1.join()終了後に下記処理が実行される。
      System.out.println("main()の処理を終わります。");
   }
}

#実行結果
C:\YJSample\15>java Sample5
1号車の処理をしています。
1号車の処理をしています。
1号車の処理をしています。
1号車の処理をしています。
1号車の処理をしています。
main()の処理を終わります。

別のスレッドの作成方法

Javaでは2つ以上のクラスから多重継承することが出来ない為
Threadクラスとそのほかのクラスの2つをスーパークラスにする事は出来ない。
このような時、クラスライブラリのRunnableインターフェイス(java.langパッケージ)
というものを使いスレッドを起動する仕組みを作ることが出来る。
Threadクラスを拡張するのではなく、Runnableインターフェイスを実装するコードを書きます。

スレッドを起動する二つの方法
・Threadクラスを拡張する
・Runnableインターフェイスを実装する
class Car implements Runnable	//Runnableインターフェイスを実装する
{	//フィールド
	private String name;
	//コンストラクタ
	public Car(String nm)
	{
		name = nm;
	}
	//run()メソッド(Runnableインターフェイスから実行したもの)
	public void run()
	{
		for(int i=0; i<5; i++) 
		{
			System.out.println(name + "の処理をしています。");
		} 
	}
}

class Sample6
{
	public static void main(String[] args)
	{	//car1で生成したCar型オブジェクトを指す
		Car car1 = new Car("1号車");
		//Thread型オブジェクトをコンストラクタにcar1オブジェクトの引数
        //引数として渡して生成する
		Thread th1 = new Thread(car1);  //Threadクラスのオブジェクトを作成する。
		th1.start();	//car1オブジェクトのrun()スレッド起動
	
		for(int i=0; i<5; i++) 
		{
			System.out.println("main()の処理をしています。");
		} 
	}
}

同期処理(synchronized)

複数のスレッドが共有するフィールドなどを処理すると
処理タイミングにより矛盾が生じる場合があります。
このような不具合を避ける為には、あるスレッドが振り込み処理を
している間は別のメソッドは処理が出来ないようにする必要があります。
メソッドにsynchronizedと言う指定を付けると、あるスレッドが
メソッドを処理している間は、他のスレッドは子のメソッドを呼び出すことが出来なくなる。
※スレッド同士の処理のタイミングを取る仕組みを同期と言う。
//会社クラス
class Company
{
   private int sum = 0;	//残金
   //synchronizedを付ける。
   public synchronized void add(int a)	//振込み処理 仮引数aは振込み額
   {
      int tmp = sum;
      System.out.println("現在、合計額は" + tmp + "円です。");
      System.out.println(a + "円稼ぎました。");
      tmp = tmp + a;	//残金に振り込み額をたし込む
      System.out.println("合計額を" + tmp + "円にします。");
      sum = tmp;	//残金を再設定
   }
}
//運転手クラス
class Driver extends Thread	//Threadクラスを継承しスレッディング処理を可能にする。
{
	//フィールド
   private Company comp;	//会社クラスのオブジェクト comp
	//コンストラクタ
   public Driver(Company c)	//引数として会社クラス型のオブジェクトをc受け取る
   {
   	comp = c;	//フィールドcomp(会社クラス型のオブジェクト)に設定
   }
   public void run()	//スレッディング処理
   {
      for(int i=0; i<3; i++){	//3回add処理を行う。
         comp.add(50);			//振込み処理
      } 
   }
}

class Sample7
{
   public static void main(String[] args)
   {
      Company cmp = new Company();	//会社オブジェクトを作成

      Driver drv1 = new Driver(cmp);	//運転手オブジェクト1を作成
      drv1.start();	//drv1のスレッド起動

      Driver drv2 = new Driver(cmp);	//運転手オブジェクト2を作成
      drv2.start(); //drv2のスレッド起動
   }
}
#実行結果
C:\YJSample\15>java Sample7
現在、合計額は0円です。
50円稼ぎました。
合計額を50円にします。
現在、合計額は50円です。
50円稼ぎました。
合計額を100円にします。
現在、合計額は100円です。
50円稼ぎました。
合計額を150円にします。
現在、合計額は150円です。
50円稼ぎました。
合計額を200円にします。
現在、合計額は200円です。
50円稼ぎました。
合計額を250円にします。
現在、合計額は250円です。
50円稼ぎました。
合計額を300円にします。



前のページへ戻る