Javaプログラミング入門
第8回
今日の講義
• スレッド
スレッドとは
• スレッド(thread)は、もともと「糸」という意
味
• Javaでは「プログラムを実行している主体」の
ことを指す
• プログラムの実行の流れに従いながらプログラ
ムを読んでいく
▫ ペンでなぞっていくと1本の糸になる
▫ このようなプログラムをシングルスレッドと言う

• 例えるなら小人が1人動いているのと同じ
シングルスレッドのイメージ図
if文を分岐しようが、
while文で繰り返そうが
どんなに複雑な処理をし
ていても一本の糸になる
マルチスレッドとは何か
• Java言語はマルチスレッドを扱うことが出来る
言語
• マルチスレッドのプログラムの場合、「いまプ
ログラムのどこを実行していますか?」と訊か
れても、「はい、ここです」と示すことは出来
ない
• マルチスレッドの場合、小人は複数人登場する
マルチスレッドのイメージ図
マルチスレッドの注意点
• マルチスレッドを考える上で注意すべき点は、
複数のスレッドが同じタイミングで同じメソッ
ドの同じ文を実行しているかもしれない、とい
うこと
▫ 独自に歩きまわっていた小人が、同時に同じ店に
入ったパターン
 互いに関わりがない間は問題は発生しない
 2人が同時に1台のレジに並ぶと?
排他制御
• 1台しかレジがない場合、小人が複数人同時に来
ても処理が出来ない
▫ 1列に並んでもらって、1度に1人ずつ会計していく

• マルチスレッドも同じで、互いに干渉しあう状
況では、スレッドは1列に並んでもらった方が安
全
▫ このような機構を排他制御(mutual exclusion
control)と呼ぶ
同期
• 普段は独立して歩き回っている小人たちに、協
力して働いてもらいたい時もある
• 情報集めをしているたくさんのスレッドが仕事
を終え、情報が全部揃ったところで、それを処
理するスレッドが動き出すようなパターン
▫ スレッドの待ち合わせやスレッドの間の通信機能
が必要
▫ このような機構を同期(synchronization)と呼ぶ
身近にあるマルチスレッドの例
• GUI(グラフィカルユーザーインターフェース)
▫ 表計算ソフトが計算を行っている時もメニュー
バーは表示されていて、ブラウジングもできる

• ネットワーク上のサーバ
▫ phpは通常シングルスレッド
※参考
http://www.php.net/manual/ja/intro.pthreads.php

• 状況を監視するようなアプリケーション
▫ タスクマネージャー
サーバとマルチスレッドの例

クライアント

通信

サーバ
スレッド

クライアント

通信
スレッド

クライアント

通信

スレッド
スレッドを作る2つの方法
• Java言語でのスレッドの作り方には2種類ある
A) Threadクラスの拡張クラスを作る
B) Runnableインターフェースを実装したクラスを
作る
Threadクラス(方法A)
• Threadクラスの拡張クラスを作ってスレッドを
動かすには、次のような手順を踏む必要がある
1.
2.
3.
4.

Threadクラスの拡張クラスを作る
そのクラスのrunメソッドを宣言する
そのクラスのインスタンスを作る
startメソッドを呼び出す
Threadクラスでスレッドを作る例
• CountTenA.java
public class CountTenA extends Thread {
public static void main(String[] args) {
CountTenA ct = new CountTenA();
ct.start();
for (int i = 0; i < 10; i++) {
System.out.println("main:i = " + i);
}
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("run:i = " + i);
}
}
}
詳しく読んでみる
• CountTenAクラスは、Threadクラスを拡張して作ら
れている
• CountTenAクラスには、2つのメソッドmainとrun
が宣言されている
▫ mainは、このクラスをアプリケーションとして実行
しようとした時に最初に呼び出されるメソッド
▫ runは、Threadクラスで宣言されているメソッドで、
スレッドが動き始めるときに呼ばれるメソッド
▫ runというメソッドは、スレッドにとってのmainメ
ソッドに相当する、と考えることが出来る
詳しく読んでみる2
• mainメソッド内の3行目、CountTenAオブジェ
クト(インスタンス)を生成しているが、ここで
はまだスレッドは動き出していない
• ct.start()
▫ このstartが実際のスレッドを起動するメソッド
▫ startメソッドの内部で、新たなスレッドが作ら
れ、そのスレッドのrunメソッドが呼び出される
糸が生まれる瞬間
startメソッドの中

新しいスレッドの誕生

runメソッドへ

startメソッドから
帰る
詳しく読んでみる3
• startメソッドが呼び出されると、新たなスレッ
ド、新たな流れ、新たな糸が生まれる。そし
て、その糸はrunメソッドで始まり、runメソッ
ドで終わる
▫ この道を歩くのは、mainスレッドの小人とは別の
小人

• runメソッドでやっていることは、変数iを0~9
までぐるぐる回してその内容を表示すること。
• 9まで表示したらfor文が終わり、このスレッド
も終了する
Runnableインターフェース(方法B)
• CountTenAでは、スレッドの実行開始点とし
て、runメソッドを宣言
• Threadクラスの拡張クラスではなくても、run
メソッドを新しいスレッドの開始点とすること
が出来る。Runnableインターフェースはrunメ
ソッドを持っており、Runnableインターフェー
スを実装するクラスは、runメソッドを実装しな
ければならない
Runnableインターフェースを使ったス
レッドを作る例
• CountTenB.java
public class CountTenB implements Runnable {
public static void main(String[] args) {
CountTenB ct = new CountTenB();
Thread th = new Thread(ct);
th.start();
for (int i = 0; i < 10; i++) {
System.out.println("main:i = " + i);
}
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("run:i = " + i);
}
}
}
クラス宣言の違い
• CountTenAは
▫ public class CountTenA extends Thread

• CountTenBは
▫ public class CountTenB implements Runnable
スレッド開始の違い
• CountTenAは

CountTenA ct = new CountTenA();
ct.start();
▫ CountTenAのメソッドstartを呼び出している
▫ CountTenAにはstartメソッドは宣言されていないが、
スーパークラスのメソッドを呼び出している

• CountTenBは

CountTenB ct = new CountTenB();
Thread th = new Thread(ct);
th.start();
▫ CountTenBのオブジェクト(インスタンス)を引数に渡
してThreadのオブジェクトを生成し、Threadクラス
のstartメソッドを呼び出している
スレッドを作る2つの方法のまとめ
A) Threadクラスの拡張クラスを宣言する
B) Runnableインターフェースを実装したクラス
を宣言する
メリット・デメリット
• 方法Aは、とにかく手軽なこと
• ただし、Javaではスーパークラスは1つしか持つこ
とが出来ないため、他のクラスの拡張クラスにする
ことはできなくなる
• 方法Bは、方法Aのデメリットを解消するために用
意された方法
• クラス階層の下の方に位置するクラスであっても、
インターフェースは実装出来る
• ただし、そのスレッドを動かすためには、別途
Threadクラスのインスタンスを生成し、そのstartメ
ソッドを呼び出す必要がある
スレッドを作る2つの方法の比較
方法A

方法B

用途

簡単なクラス向け

複雑なクラス向け

スーパークラス

Threadクラス

なんでも良い

クラスの宣言

Threadクラスの拡張
class CountTenA extends
Thread {
....
}

Runnableインターフェースの実装
class CountTenB implements
Runnable {
....
}

スレッドの起動

startメソッドを呼ぶ
CountTenA a = new
CountTenA();
a.start();

Thread経由でstartを呼ぶ
CountTenB b = new CountTenB();
Thread th = new Thread(b);
th.start();

実行開始点

runメソッド

runメソッド
インターフェースの設計
• スレッドに限った話ではなく、インターフェー
ス設計の全般に適応出来る
• つまり、ある機能を持ったクラスを作りたい
時、1つはその機能を持ったクラスの拡張クラス
にしてしまう方法、もう1つは、その機能を実現
するためのメソッドをまとめてインターフェー
スにし、そのインターフェースを実装するクラ
スを作る方法がある
演習問題1
• 「こんにちは!」というあいさつを1秒おきに表
示するPrintHelloクラスと、それを実現するス
レッドとなるLabelPrinterクラスを次のように作
ろうとしている。誤りがあるため、実行結果が
以下のようになるよう修正しなさい。
• 【実行結果】
こんにちは!
こんにちは!
こんにちは!
... ←続く
LabelPrinter.java
public class LabelPrinter {
String label = "no label";
public LabelPrinter(String label) {
this.label = label;
}
@Override
public static void run() {
while (true) {
System.out.println(label);
Thread.sleep(1000);
}
}
}
PrintHello.java
public class PrintHello {
public static void main(String[] args) {
LabelPrinter th = new LabelPrinter("こ
んにちは!");
th.start();
}
}
2つのスレッドが同じフィールドに代入
したらどうなるか?
• 次のクラスBadBankは「悪い銀行」を表すクラ
ス
• 1つのフィールドvalueと1つのメソッド
addMoneyを持つ
• addMoneyは預入と引出を行うメソッド
• addMoneyの引数が0より大きい時は預入、0よ
り小さい時は引出しを表す
2つのスレッドが同じフィールドに代入
する例
• BadBank.java
public class BadBank {
// 預金残高
private int value = 0;
// 預入・引き出し
public 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から出ました");
}
}
BadBankを使う例
public class BadBankTest extends Thread {
BadBank bank;
public BadBankTest(BadBank bank) {
this.bank = bank;
}
@Override
public void run() {
while(true) {
// 100円預入
bank.addMoney(100);
// 100円引出し
bank.addMoney(-100);
}
};
public static void main(String[] args) {
BadBank bank = new BadBank();
// 2つのスレッドで同じインスタンスを扱う
new BadBankTest(bank).start();
new BadBankTest(bank).start();
}
}
なぜ矛盾は発生するのか?
• 現在残高を保存する
int currentValue = value;

という部分と、矛盾チェックを行う
if (currentValue + money != value) {
....
}

という部分の間で、「スレッドの切り替え」が起こ
る可能性があるから
▫ 1つのスレッドが現在残高を保存し、矛盾がないか
チェックする前に、別のスレッドがvalueにmoneyを
足し込んでしまうから!
2つのスレッドが同じフィールドに代入
する正しい例
• 違いはたった1つ
▫ synchronized

というキーワードが、addMoneyメソッドにつ
いただけ
• このキーワードを付けるだけで、先ほどの矛盾
が発生しなくなる
BadBankを直したGoodBank
public class GoodBank {
// 預金残高
private int value = 0;
// 預入・引き出し
public 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から出ました");
}
}
GoodBankを使う例
public class GoodBankTest extends Thread {
GoodBank bank;
public GoodBankTest(GoodBank bank) {
this.bank = bank;
}
@Override
public void run() {
while(true) {
// 100円預入
bank.addMoney(100);
// 100円引出し
bank.addMoney(-100);
}
};
public static void main(String[] args) {
GoodBank bank = new GoodBank();
new GoodBankTest(bank).start();
new GoodBankTest(bank).start();
}
}
どうして矛盾が発生しないのか?
• addMoneyにsynchronizedを付けた時、1つのス
レッドがaddMoneyを実行中であれば、他のス
レッドはaddMoneyを実行することが出来ない
ため
GoodBankの様子
変数bank
GoodBankのインスタンス

他のスレッドは
待たされる

public synchronized void addMoney(int money)
{
ロック
}

スレッド1が実行中
ロック(lock)
• 「鍵」のこと
• 部屋に1人でいたい時、部屋に入って鍵をかけ
る。
• 他の人は部屋に入ってこれなくなる
• スレッドは、synchronizedが付いたメソッド
(synchronizedメソッド)に入るときに、鍵をか
け、そのメソッドから出る時に、鍵を外す
• これにより、そのメソッドに入れるスレッドは1
つだけになる
鍵をかけている「部屋」とは?
• スレッドがsynchronizedメソッドに入るときに
は、そのインスタンスに対して鍵をかけている
• 1人の小人(スレッド)がその部屋(インスタンス)
に鍵をかける(ロックをかける)と、他の小人は
その部屋(インスタンス)の鍵のある部屋
(synchronizedメソッド)には入れない
• synchronizedはメソッドに鍵をかけているわけ
ではなく、インスタンスにかけている
synchronized
• あるスレッドがsynchronizedメソッドを実行し
ている最中であっても、そのインスタンスの
synchronizedではないメソッドならば、どのス
レッドも実行できる
• あるスレッドがsynchronizedメソッドを実行し
ていても、別のインスタンスメソッドは、
(synchronizedであってもなくても)実行できる
• 1つのスレッドは、1つのインスタンスの
synchronizedメソッドを続けて実行出来る(自分
自身が鍵によって締め出されることはない)
synchronizedメソッドとsynchronized
ブロック
• メソッド全体ではなく、メソッドの一部分だけ
でロックをかけることができる
synchronized(ロックオブジェクト) {
....
}
• この場合には、ロックをかけるオブジェクトを
明示的に指定する
addMoneyの例
public void addMoney(int money) {
synchronized (this) {
// 現在残高を保存
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から出ました
");
}
}
演習問題2
• 演習問題1のLabelPrinterを使って、「おはよ
う!」「こんにちは!」「こんばんは!」をそ
れぞれ表示するスレッド3つを動かすクラス
PrintHello3を宣言しなさい
演習問題3
• CountTenA.javaではrunメソッドを実行してい
るのは、1つのスレッドだった。新たなスレッド
を1つだけ生成するのではなく、3個生成して動
作するようにプログラムを書き換えなさい。ク
ラスの名前はCountTen3とする。
• また、表示を行っているのはどのスレッドかわ
かるようにしなさい。必要であれば、次のメ
ソッドを使用すること。
▫ public final String getName()
▫ public static Thread currentThread()
クラスメソッドとsynchronized
• メソッドにはインスタンスメソッドとクラスメ
ソッドの2種類がある
• どちらにもsynchronizedメソッドにすることが
出来る
• ただし、クラス・メソッドがsynchronizedメ
ソッドになっているとき、ロックしているもの
は何か?
▫ インスタンスメソッドの時は、インスタンス自身
(this)をロックしていたが、クラスメソッドの場
合は、クラス自身をロックすることになる
スレッドを止めるには?
• スレッドはrunメソッドの実行が終了すれば、その
スレッドは動いていなくなる
• スレッドが自分で自分を終了したい場合には、run
メソッドを終わらせればよい
• 次のrunメソッドはdoCommandを1000回実行する
と止まる
public void run () {
for (int i = 0; i < 1000; i++) {
doCommand();
}
}
自分以外のスレッドを終了させるに
は?
• スレッドに前もって「終了するための条件」を埋め込んでお
き、外からその条件を操作すればよい
public class Runner extends Thread {
private boolean running = true;
public void stopRunning() {
running = false;
}
@Override
public void run() {
while (running) {
doCommand();
}
}
}
スレッドを少し待たせたい場合はどう
する?
• スレッドの動作が速すぎて不都合があるとき
• メソッドを繰り返し呼ぶ必要があるが、時間間
隔を開けたいとき
待ちたいときにはThread.sleep
public class Periodic {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int tm = i * 1000;
System.out.println("Start sleep:tm = " +
tm);
try {
Thread.sleep(tm);
} catch (InterruptedException e) {

}

}

}

}
演習問題4
• 約3秒毎に"***"を10回表示するスレッドと、約5秒ごとに
"====="を10回表示するスレッドを、それぞれ1つずつ動か
すクラスをThreadクラスの拡張クラスとして作りなさい。
• 【実行例】※実行する度に変化する
***
=====
***
***
=====
***
=====
***
***
=====
演習問題5
• 演習問題4をRunnableインターフェースを実装
して作成しなさい
スレッドの終了を待つにはどうする?
• 他のスレッドに仕事をさせておき、そのスレッ
ドの実行が終了したら自分の仕事を再開したい
とき、Threadのjoinというメソッドを使用する
• joinの引数にタイムアウト時間を指定すること
も出来る
スレッドの終了を待つjoin
public class JoinTest extends Thread {
public static void main(String[] args) {
JoinTest th = new JoinTest();
System.out.println("main:はじめ");
th.start();
System.out.println("main:終了待ちに入る");
try {
th.join();
} catch (InterruptedException e) {
System.out.println(e);
}
System.out.println("main:おわり");
}
スレッドの終了を待つjoin
@Override
public void run() {
System.out.println("run:スレッド実行開始");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println(e);
}
System.out.println("run:スレッド実行終了");
}
}
スレッド同士を待ち合わせたいときは
どうする?
• 複数のスレッドはまったく別のところを走って
いるけども、片方のスレッドが別のスレッドか
ら通知が来るのを待つような状況
▫ スレッドPは、データを次々に作って配列に格納
する
▫ スレッドCは、配列に格納されたデータを次々に
処理する

• スレッドPは生産者(Producer)、スレッドCは
データの消費者(Consumer)を表すとする
スレッドの待ち合わせ
• スレッドPが先行した場合には、キューは一杯
になってしまい、スレッドCがデータを消費し
て、キューに空き領域を作るまで、スレッドP
は待たされる
• スレッドCが先行した場合は、キューは空に
なってしまい、スレッドPがデータを生産し
て、キューに詰めるまで、スレッドCは待たさ
れる
スレッドの待ち合わせの例
• クラス構成
▫ ProducerConsumerクラス(mainメソッド)
▫ MyQueueクラス(スレッドPとスレッドCが参照す
る配列)
▫ Producerクラス(Threadを継承、キューにデータ
を入れる)
▫ Consumerクラス(Threadを継承、キューのデータ
を消費する)
ProducerConsumer.java
public class ProducerConsumer {
public static void main(String[] args) {
MyQueue queue = new MyQueue(3);
Producer producer = new
Producer(queue);
Consumer consumer = new
Consumer(queue);
producer.start();
consumer.start();
}
}
MyQueue.java(1)
public class MyQueue {
int[] intbuf;
int start;
int count;
public MyQueue(int size) {
intbuf = new int[size];
start = 0;
count = 0;
}
public synchronized void put(int n) throws InterruptedException {
while (count >= intbuf.length) {
System.out.println(Thread.currentThread().getName() + " wait : バッ
ファの空きを待つ");
wait();
}
int end = (start + count) % intbuf.length;
intbuf[end] = n;
count++;
notifyAll();
}
MyQueue.java(2)
public synchronized int take() throws InterruptedException {
while (count == 0) {
System.out.println(Thread.currentThread().getName() + "
wait : データを待つ");
wait();
}
int n = intbuf[start];
start = (start + 1) % intbuf.length;
count--;
notifyAll();
return n;
}
}
Producer.java(1)
public class Producer extends Thread {
static final int END = -1;
MyQueue queue = null;
public Producer(MyQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 100; i++) {
int n = produce(i);
queue.put(n);
}
queue.put(Producer.END);
} catch (InterruptedException e) {
System.out.println(e);
}
};
Producer.java(2)
int produce(int n) {
sleepRandomly();
System.out.println("Producer: " + getName() + "
は " + n + " を生産完了");
return n;
}
void sleepRandomly() {
try {
int n = (int) Math.random() * 1000;
Thread.sleep(n);
} catch (InterruptedException e) {
}
}
}
Consumer.java(1)
public class Consumer extends Thread {
MyQueue queue = null;
public Consumer(MyQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while(true) {
int n = queue.take();
if (n == Producer.END) {
break;
}
consume(n);
}
} catch (InterruptedException e) {
}
}
Consumer.java(2)
void consume(int n) {
System.out.println("Consumer: " +
getName() + " は " + n + " を消費中");
sleepRandomly();
}
void sleepRandomly() {
try {
int n = (int) Math.random() * 1000;
Thread.sleep(n);
} catch (InterruptedException e) {
}
}
}
ProducerConsumerクラス
• このクラスは以下の処理を行う
1. MyQueueのインスタンスを生成する。キューの大き
さは3とする
2. 生産者スレッドproducerを生成する。通信用の
キューを渡す
3. 消費者スレッドconsumerを生成する。通信用の
キューを渡す
4. 生産者スレッドproducerを起動する
5. 消費者スレッドconsumerを起動する

•

これ以降は、producerとconsumer2つのスレッド
が独自に、キューを共有しながら動く
MyQueueクラス
• スレッドの制御を行いながらデータの出し入れ
を行うクラス
• マルチスレッドの環境でも正しく動作するクラ
スやメソッドのことをスレッドセーフ(thread
safe)と呼ぶ
条件待ちの決まり文句
synchronized aMethod(...) throws
InterruptedException {
while( ! 求めている条件) {
wait();
}
必要な処理を行う
notifyAll();
}
MyQueueクラス
• putメソッド
▫ 引数nをデータとして格納するメソッド
▫ intbufが一杯ならば、そのスレッドは待ち状態になる
▫ 他のスレッドがnotifyAllすると、スレッドは動作可能
状態になる

• takeメソッド
▫ キューからデータを抜き出すメソッド
▫ キューが空だったら、waitメソッドで待ち状態に入る
▫ 他のスレッドがnotifyAllすると、動き始め、条件がみ
たされたことを確認するとwhile文を抜ける
条件のチェックの部分は、なぜifでは
なくwhileなのか?
• while (count >= intbuf.length)
• waitで待っていたスレッドが動き出した、とい
うのは、単に誰かがnotify(あるいはnotifyAll)し
たというだけのことで、そのスレッドがwaitし
ていた条件が満たされたとは限らないから
• つまり、スレッドがwaitの呪縛から逃れて実際
の処理に向かう時、もう一度条件をチェックす
る必要がある。
waitやnotify、notifyAllを発行するとき
のメソッドはなぜsynchronizedでなけ
ればならないか?
• 必ずしもsynchronizedメソッドである必要はな
いが、wait、notify、notifyAllを実行するとき、
対象となるオブジェクトにロックをかけていな
ければならない
• ロックをかける代表的な方法がsynchronizedメ
ソッド
synchronizedの中でwaitしてもいいの
か?
• synchronizedの中では、そのオブジェクトに関
して1つのスレッドしか動けないが、waitしても
いいのだろうか?
• waitは、そのスレッドが持っているそのオブ
ジェクトのロックを一旦外すので、良い
• waitを発行するとsynchronizedブロックの前で
待っていたスレッドが動作可能状態になる。
• Thread.sleepはオブジェクトのロックははずさ
ない
waitはどのクラスのメソッドか?
• waitはObjectクラスのメソッド
• すなわち、Javaのオブジェクトはすべてロック
対象になる
• スレッドは、waitメソッドを実行するとオブ
ジェクトごとに用意されたウエイトセット(wait
set)という待合室にはいり、notifyされるまで実
行を一時停止する
notifyAllしたら、waitしていたスレッ
ドはすぐ動くのか?
• 「実行可能状態」にはなるが、すぐに動き出す
わけではない
• notifyAllを発行したスレッドがそのオブジェク
トのロックを開放しない限り、他のスレッドは
走り出さない
notifyとnotifyAllの違いは何か?
• notifyは、ウエイトセットの中にある1つのス
レッドだけを実行再開する
• notifyAllはウエイトセットの中にあるスレッド
をすべて実行再開する
匿名クラスでインスタンス生成
• Runnableはインターフェースなので、newでインス
タンス生成することはできない
• しかし、以下のようなコードなら書くことが出来る
Runnable r = new Runnable() {
@Override
public void run() {
...
}
}
r.start();
• この名前のないクラスのことを匿名クラスという
演習問題6
• GoodBankTest.javaはGoodBankのインスタンス
を生成して、預金の預入と引出しを行った。
• これを変更して、銀行口座がたった1つしかない
プログラムにしなさい。クラスの名前は
OneBankTestとOneBankにすること。
• ヒント:OneBankのフィールドやメソッドを
staticにし、それに合わせてOneBankTestを作成
する
演習問題7
• 次のSingleThreadProgramクラスはJob(仕事)ク
ラスのオブジェクトを10個作ってworkというメ
ソッドを呼び出し続けるクラスである。このプ
ログラムをマルチスレッドに書き換えなさい。
Job.java
public 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) {
}
}
public String toString() {
return "[Job " + num + "]";
}
}
SingleThreadProgram.java
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();
}
}
}
参考文献
• Java言語 プログラミングレッスン[第3版]下
▫ 結城浩[著]

Javaプログラミング入門【第8回】