Thread とは
Thread (スレッド) とは 処理を実行する流れの単位 を示す。
パソコン操作についてまとめるなら、
この一連の処理がThread(スレッド)とイメージすると良い。
#シングルスレッド & マルチスレッド
シングルスレッド(左図): 1つの処理だけで終了するスレッド
マルチスレッド(右図): 複数のスレッドが同時に動くスレッド
このようにイメージできる。
###マルチスレッドの利点
シングルスレッドよりも高速な処理が可能である。
For example)
Microsoft Wordで作業中、同時にスペルチェックが行われていたり,単語数を表示したりしている。
これがマルチスレッドの真骨頂である。
#Thread(スレッド)の基本操作
- クラスにRunnableインターフェースを実装する。
class クラス名 implements Runnable{
public void run(){
/* 処理を書く */
}
}
- Threadのコンストラクタの引数としてRunnableを実装したクラスを渡し、宣言します。
Thread thread = new Thread(クラス型変数);
Thread型のコンストラクタのリファレンスは以下。
Thread
public Thread(Runnable target)
- Threadの起動
start()メソッドでクラス内のrun()メソッドを実行できます。
thread.start();
- Threadが終了したかを確認する
Threadのjoin()メソッドを使用します。
*今回はThreadが配列で複数あると仮定します。
try{
for(int i=0; i<thread.length; i++){
thread[i].join();
}
} catch(InterruptedException ie){
ie.printStackTrace();
}
###スレッドありとなしの違い
変数sumに1を加算する。
これを1000000000回繰り返すプログラムについてスレッド有無の場合による実行時間の検証。
####スレッドなしの場合
import java.util.Date;
import java.math.BigInteger;
public class NoThread{
private static BigInteger N = new BigInteger("1000000000");
private static BigInteger sum = BigInteger.ZERO;
public static void main(String[] args){
long start_time = new Date().getTime();
calculate();
long end_time = new Date().getTime();
output(start_time, end_time);
}
public static void calculate(){
BigInteger i = BigInteger.ZERO;
while(!i.equals(N)){
sum = sum.add(BigInteger.ONE); // sum += i
i = i.add(BigInteger.ONE); // i++
}
}
public static void output(long s, long e){
System.out.println("Sum: "+sum);
System.out.println("total time: "+(e-s)+"ms");
}
}
Thread数 | 実行時間 |
---|---|
なし | 46371 ms |
*処理にかかる時間は常に一定ではない。 |
####スレッドありの場合
今回は実行時の引数にスレッド数を指定します。
import java.math.BigInteger;
import java.util.Date;
public class ThreadRun{
private static BigInteger N = new BigInteger("1000000000");
private static BigInteger sum = BigInteger.ZERO;
public static void main(String[] args){
int num_threads = Integer.parseInt(args[0]);
BigInteger range = N.divide(new BigInteger(args[0]));
ThreadRunnable[] tr = new ThreadRunnable[num_threads];
Thread[] t = new Thread[num_threads];
BigInteger low = BigInteger.ONE;
BigInteger high = low.add(range);
long start_time = new Date().getTime();
for(int i=0; i<num_threads-1; i++){
tr[i] = new ThreadRunnable(low, high);
t[i] = new Thread(tr[i]);
t[i].start();
low = high.add(BigInteger.ONE);
high = low.add(range);
}
tr[num_threads-1] = new ThreadRunnable(low, high);
t[num_threads-1] = new Thread(tr[num_threads-1]);
t[num_threads-1].start();
try{ // check whether threads finished
for(int i=0; i<num_threads; i++){
t[i].join();
}
} catch(InterruptedException ie){
ie.printStackTrace();
}
for(int i=0; i<num_threads; i++){
sum = sum.add(tr[i].getSum());
}
long end_time = new Date().getTime();
System.out.println("Sum: "+sum);
System.out.println("total time: "+(end_time-start_time)+"ms");
}
protected static class ThreadRunnable implements Runnable{
private BigInteger sum_temp;
private BigInteger low, high;
public ThreadRunnable(BigInteger l, BigInteger h){
this.low = l;
this.high = h;
this.sum_temp = BigInteger.ZERO;
}
@Override
public void run(){
while(!low.equals(high)){
sum_temp = sum_temp.add(BigInteger.ONE); // sum_temp += low
low = low.add(BigInteger.ONE); // low++;
}
}
public BigInteger getSum(){
return sum_temp;
}
}
}
Thread数 | 実行時間 |
---|---|
8 | 26840 ms |
16 | 26462 ms |
*処理にかかる時間は常に一定ではない。 |
#####まとめ
スレッドありの場合の方がスレッドなしよりも処理時間が短くなりました。
スレッドを有効活用することで大幅に時間を削減することができる。
だが、スレッドを増やしすぎてしまうと逆に実行時間が多くなるので適切なスレッド数を指定するのが重要。