<概要>もっと!モット!スレッドを学びます。復習です。
●例題16-3-1 次のシングルスレッドプログラムをマルチスレッドに書き換えて下さい。
○シングルスレッドプログラム
class Job{
int num;
public Job(int n){
num=n;
}
public void work(){
System.out.println(this+" is working.");
try{
int n=(int)(Math.random()*10000);
Thread.sleep(n);
}catch(InterruptedException e){
System.out.println(e);
}
}
public String toString(){
return "[Job "+num+"]";
}
}
public class SingleThreadProgram{
Job[] jobs;
public SingleThreadProgram(int jobcount){
jobs=new Job[jobcount];
for(int i=0;i<jobcount;i++){
jobs[i]=new Job(i);
}
}
public void workAllJobs(){
for(int i=0;i<jobs.length;i++){
jobs[i].work();
}
}
public static void main(String[] args){
SingleThreadProgram self=new SingleThreadProgram(10);
while(true){
self.workAllJobs();
}
}
}
○マルチスレッドプログラム1
class JobThread extends Thread{
Job job;
public JobThread(int n){
job=new Job(n);
}
public void run(){
while(true){
job.work();
}
}
}
public class MultiThreadProgram1{
public MultiThreadProgram1(int jobcount){
for(int i=0;i<jobcount;i++){
new JobThread(i).start();
}
}
public static void main(String[] args){
new MultiThreadProgram1(10);
}
}
○マルチスレッドプログラム2
class RunnableJob extends Job implements Runnable{
public RunnableJob(int n){
super(n);
}
public void run(){
while(true){
work();
}
}
}
public class MultiThreadProgram2{
public MultiThreadProgram2(int jobcount){
for(int i=0;i<jobcount;i++){
new Thread(new RunnableJob(i)).start();
}
}
public static void main(String[] args){
new MultiThreadProgram2(10);
}
}
○実行例(シングルスレッド)
……
[Job 0] is working.
[Job 1] is working.
[Job 2] is working.
[Job 3] is working.
[Job 4] is working.
[Job 5] is working.
[Job 6] is working.
[Job 7] is working.
[Job 8] is working.
[Job 9] is working.
[Job 0] is working.
[Job 1] is working.
[Job 2] is working.
……
○実行例(マルチスレッド)
……
[Job 1] is working.
[Job 2] is working.
[Job 0] is working.
[Job 3] is working.
[Job 9] is working.
[Job 4] is working.
[Job 7] is working.
[Job 8] is working.
[Job 5] is working.
[Job 7] is working.
[Job 7] is working.
[Job 1] is working.
[Job 8] is working.
……
○解説
プログラムは理解できたと思います。
シングルスレッドとマルチスレッドで同じことをしています。
それでは、実行速度はどうでしょう?
マルチスレッドは本当に速いのか?
実際に実行してみると分かりますが、
マルチスレッドの方が圧倒的に速いです。
何故でしょう?
待ち時間の合計は同じはずでは?
これには、一つの可能性が考えられます。
すなわち、sleep メソッドで一時停止する時間はスレッドが切り替わってもカウントされ続ける。
もし仮に待ち時間が無いのであれば、
シングルスレッドとマルチスレッドの実行速度は同じということになりますね。
●例題16-3-2 例題16-4 GoodBank クラスのフィールド、メソッドを static にして全体を書き換えて下さい。
○プログラム
//OneBank.java
public class OneBank{
private static int value=0;
public static synchronized void addMoney(int money){
int currentValue=value;
System.out.println(Thread.currentThread()+" が addMoney に入りました。");
value+=money;
if(currentValue+money!=value){
System.out.println(Thread.currentThread()+" で矛盾が発生しました!");
System.exit(-1);
}
System.out.println(Thread.currentThread()+" が addMoney から出ました。");
}
}
//OneBankTest.java
public class OneBankTest extends Thread{
public void run(){
while(true){
OneBank.addMoney(100);
OneBank.addMoney(-100);
}
}
public static void main(String[] args){
new OneBankTest().start();
new OneBankTest().start();
}
}
○実行結果
……
Thread[Thread-0,5,main] が addMoney に入りました。
Thread[Thread-0,5,main] が addMoney から出ました。
Thread[Thread-1,5,main] が addMoney に入りました。
Thread[Thread-1,5,main] が addMoney から出ました。
……
○解説
OneBank クラスのインスタンスフィールド value をクラスフィールドに変更し、
インスタンスメソッド addMoney をクラスメソッドに変更したことで、
OneBankTest クラスにもいくらかの変更が加えられましたが、
その殆どは OneBank クラスのインスタンスを廃したことでしょう。
クラスフィールドはクラスにつき一つしか作られないフィールド。
synchronized クラスメソッドは呼び出すのにインスタンスを必要とせず、
クラスにつき一つのスレッドしか同時に実行することが出来ないメソッドでした。
プログラムでは同じクラスのスレッドを二つ作成していますが、
synchronized クラスメソッドを実行できるのは一方のみです。
したがって、二人のお客に対し、窓口は一つしかないのと同じ、ということになります。
それに対し、例題16-4のプログラムの場合は、
窓口は幾つもあるのに、二人のお客が一つの窓口に並んでいる、といったところでしょうか。
★スレッドを強制的に切り替えるには?
いつスレッドの切り替えが起こるかは予測不能です。
しかし、任意のタイミングでスレッドの切り替えを起こすことは可能です。
もちろん、ここでしかスレッドの切り替えが起こらない、という意味ではありませんけどね。
public static void yield() //Thread クラス
現在実行中のスレッドオブジェクトを一時的に休止させ、ほかのスレッドが実行できるようにします。