8-1. Thread

Thread の基礎

Java で並列にプロセスを動かすには、 java.lang.Thread クラスを継承し ます。 そして、 void run()メソッドをオーバライドします。 プロセスを起動するときは、クラスのインスタンスに対して、 start() メソッドを呼び出すと、オーバライドしたメソッドが並列に起動されます。

起動したプロセスを終了するまで待つには join() メソッ ドを呼び出すと、終了するまで待たされます。

例8-1

git://edu.net.c.dendai.ac.jp/git/spro/8/1

Thread1.java

public class Thread1 extends Thread {
	private static int serial=0;
	private int num;
	public Thread1() {
		num=serial++;
	}
	@Override
	public String toString() {
		return "Thread"+num;
	}
	@Override
	public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			System.out.println("Interruputed");
		}
		System.out.println(this);
	}
}
Main.java

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class Main {
	private static final int n = 10;
	public static void main(String[] args) {
		@SuppressWarnings("unchecked")
		Supplier<String>[] testList = new Supplier[]{
				()->testRun(),
				()->testStart(),
				()->testJoin(),
		};
		long prev,now;
		prev=System.currentTimeMillis();
		for(Supplier<String> test : testList) {
			System.out.println(test.get());
			now = System.currentTimeMillis();
			System.out.println(now-prev);
			prev=now;
		}
	}
	private static List<Thread> getTList() {
		List<Thread> tlist = new ArrayList<>();
		for(int i=0; i<n; i++) {
			tlist.add(new Thread1());
		}
		return tlist;
	}
	private static String testRun() {
		List<Thread> tlist = getTList();
		for(Thread t : tlist) {
			t.run();
		}
		return "TestRun finished.";
	}
	
	private static String testStart() {
		List<Thread> tlist = getTList();
		for(Thread t : tlist) {
			t.start();
		}
		return "TestStart finished.";
	}
	private static String testJoin() {
		List<Thread> tlist = getTList();
		for(Thread t : tlist) {
			t.start();
		}
		for(Thread t : tlist) {
			try {
				t.join();
			} catch (InterruptedException e) {
			}
		}
		return "TestJoin finished.";
	}
}

Interrupted

起動しているプロセスを途中で止めるには、いくつか非推奨のメソッドが ありますが、それらを使わずに、 interrupt メソッドの呼び出しで行い ます。

interrupt メソッドでは、オブジェクトの状態を変え、 super.interrupt() を呼び出して終えるようにします。

super.interrupt メソッドにより、Thread クラスに InterruptedException が発生します。 これにより、実行中の sleep, join, wait メソッドが中断し、例外処理 を行います。

処理を中断する際、終了処理を確実に実施して終了するようにするのが肝 要です。

ThreadGroup

Thread の集まりをコントロールするために、java.lang.ThreadGroup が あります。 ThreadGroup のインスタンスを予め作成しておき、Thread を作成すると きに、Thread のコンストラクタに ThreadGroup のインスタンスを

例8-2

git://edu.net.c.dendai.ac.jp/git/spro/8/2

Thread2.java

public class Thread2 extends Thread {
	private static int serial=0;
	private int num;
	private long dulation;
	public Thread2(long dulation, ThreadGroup sg, String str) {
		super(sg,str);
		this.dulation = dulation;
		num=serial++;
	}
	@Override
	public String toString() {
		return "Thread"+num;
	}
	@Override
	public void interrupt() {
		super.interrupt();
	}
	@Override
	public void run() {
		try {
			Thread.sleep(dulation);
		} catch (InterruptedException e) {
			System.out.println(this+" is Interruputed");
		}
		System.out.println(this+" is finished");
	}
}
Main.java

import java.util.Scanner;
public class Main {
	private static final int n = 10;
	private static long dulation = 20000;
	public static void main(String[] args) {
		ThreadGroup sg = new ThreadGroup("");
		System.out.println("start");
		for(int i=0; i<n; i++) {
			new Thread2(dulation,sg,"").start();
		}
		Scanner sc = new Scanner(System.in);
		sc.nextLine();
		sc.close();
		sg.interrupt();		
	}
}

8-2. 演習

演習8-1

以下のプログラムで、配列の一部分の合計を求めるクラス Thread3 を作 成しなさい。

git://edu.net.c.dendai.ac.jp/git/spro/8/3

Main.java


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
	final private static int n=10000000;
	final private static int k=10;
	public static void main(String[] args) throws InterruptedException {
		double[] a = getRandom(n);
		long[] t = new long[3];
		double[] result = new double[2];

		t[0] = System.currentTimeMillis();
		List<Thread3> tlist = new ArrayList<>();
		for(int i=0; i<k; i++) {
			Thread3 thread = new Thread3(a,i*n/k,(i+1)*n/k-1);
			thread.start();
			tlist.add(thread);
		}
		result[0]=0;
		for(Thread3 thread : tlist) {
			thread.join();
			result[0] += thread.getValue();
		}
		t[1] = System.currentTimeMillis();
		result[1]=Arrays.stream(a).sum();
		t[2] = System.currentTimeMillis();
		for(int i = 0; i < 2; i++) {
			System.out.println(result[i]);
			System.out.println(t[i+1] - t[i]);
		}
	}
	private static double[] getRandom(int n2) {
		double[] result = new double[n2];
		for(int i=0; i<n2; i++ ) {
			result[i] = Math.random();
		}
		return result;
	}
}