戦国IT - 情報処理技術者試験の過去問対策サイト
ブログお知らせお問い合わせ料金プラン

基本情報技術者 2012年 秋期 午後 問11


次のJavaプログラムの説明及びプログラムを読んで、設問1,2に答えよ。

〔プログラムの説明〕  スレッドを利用してタイマ処理を行うプログラムである。タイマ処理の基本機能は、秒単位で指定した時間(以下、遅延時間という)が経過したときに、インタフェースで指定したメソッドを呼び出すことである。次のクラス及びインタフェースから成る。
(1) クラスTimerは、タイマ処理の機能を定義し実装する。  ① クラスメソッドcreateTimer:クラスTimerのインスタンス(以下、タイマという)を生成し、直ちにタイマ処理を開始する。引数で、タイマの名前、インタフェースTimerActionを実装するインスタンス及び遅延時間を指定する。  ② メソッドgetName:タイマの名前を返す。  ③ メソッドcancel:タイマ処理をキャンセルする。  ④ メソッドclose:タイマ処理が終了するまで待機する。  ⑤ 内部クラスWorker:タイマ処理を実装し、そのインスタンスは、スレッドとして実行される。実行スレッドは、スレッド名Timer-n(nは0から始まるスレッド生成のシーケンス番号)が与えられ、次の処理を行う。   (a) 現在時刻に、タイマの生成時に指定された遅延時間を加えて、タイマの終了時刻を設定する。   (b) 実行開始時に、タイマの生成時に指定されたTimerActionのインスタンスに開始の事象を通知する。   (c) 開始通知後、スレッドは終了時刻になるまで休止する。   (d) 終了時刻になったとき、終了の事象をTimerActionのインスタンスに通知し、タイマ処理の実行を終了する。   (e) タイマ処理がキャンセルされた場合は、終了時刻になるのを待たずにキャンセルの事象をTimerActionのインスタンスに通知し、タイマ処理の実行を終了する。  ここで、フィールドcanceledは、複数スレッドから非同期にアクセスされるのでvolatile修飾子を付けて宣言しておく。
(2) インタフェースTimerActionは、タイマ処理で事象が発生したときにタイマから事象の通知を受けるメソッドを定義する。タイマを利用するプログラムは、このインタフェースの全メソッドを実装しなければならない。各メソッドの引数は、事象が発生したTimerのインスタンス及び事象発生の時刻である。  ① メソッドonStart:タイマ処理の開始時に呼び出される。  ② メソッドonAlarm:タイマ生成時に指定した遅延時間が経過したときに呼び出される。  ③ メソッドonCancel:タイマ処理がキャンセルされたときに呼び出される。
 クラスTimerTestは、タイマ処理のテストプログラムである。メソッドmainは、TimerTestのインスタンスを生成し、メソッドtestを実行する。testは、二つのタイマを生成し、終了を待つ。メソッドonAlarmが、shortTimerを引数として呼び出された場合、longTimerのタイマ処理をキャンセルする。
 このテストを実行したところ、図1の結果が得られた。プログラムの実行速度は十分に速いものとし、各メソッドの処理時間は秒単位の時刻の測定に影響がないものとする。
基本情報技術者試験(平成24年 午後 問11 図1)
基本情報技術者試験(平成24年 午後 問11 プログラム1)
基本情報技術者試験(平成24年 午後 問11 プログラム2)
基本情報技術者試験(平成24年 午後 問11 プログラム3)

設問1:

問題文を見る
 プログラム中のに入れる正しい答えを、解答群の中から選べ。   aに関する解答群  ア:(delta = endAt + currentTime()) < 0  イ:(delta = endAt + currentTime()) > 0  ウ:(delta = endAt - currentTime()) < 0  エ:(delta = endAt - currentTime()) > 0   bに関する解答群  ア:break  イ:canceled = false  ウ:continue  エ:delta = 0  オ:endAt = 0  カ:return   c, dに関する解答群  ア:expands  イ:extends  ウ:implements  エ:subclasses  オ:throw  カ:throws   eに関する解答群  ア:longTimer  イ:new Runnable()  ウ:new Timer()  エ:new TimerAction()  オ:shortTimer  カ:this   fに関する解答群  ア:longTimer.cancel()  イ:onCancel(longTimer, instant)  ウ:onCancel(shortTimer, instant)  エ:onCancel(timer, instant)  オ:shortTimer.cancel()  カ:timer.cancel()

模範解答

a:エ、b:ア、c:ウ、d:カ、e:カ、f:ア

解説

解答の導き方

空欄は、タイマの残り時間を調べる処理、キャンセル時の動き、Javaのクラス宣言や例外の書き方を順に確認すると判断できます。
a:終了時刻まで待つ条件
Workerのコンストラクタでは、終了時刻を「現在時刻に遅延時間を加えた時刻」として設定しています。したがって、現在時刻を終了時刻から引くと、終了までの残り時間になります。
残り時間が正の間は、終了時刻に達していません。そのため、その時間だけ休止する必要があります。よって、whileの条件は「deltaが0より大きい間」です。選択肢ではエに当たります。
b:キャンセル時にループを抜ける処理
cancelメソッドは、キャンセルされたことを示すcanceledをtrueにし、実行中のスレッドにinterruptを呼び出します。interruptは、休止中のスレッドに中断を知らせる操作です。その結果、Thread.sleep(delta)で休止しているスレッドではInterruptedExceptionが発生します。
キャンセルされた場合は、休止を続けずにループを抜けます。ループの後には、canceledがtrueならonCancelを呼び出す処理があります。そこで必要なのはbreakです。選択肢ではアです。
continueではループを抜けず、終了時刻まで待つ処理に戻ってしまいます。returnではrunメソッド自体が終わり、ループの後にあるonCancelの呼出しまで進みません。
c:TimerActionを実装する宣言
TimerTestにはonStart、onAlarm、onCancelが定義されています。これらはTimerActionで定められたメソッドです。
クラスがインタフェース(必要なメソッドの形を定めた約束)を実装するときは、implementsを使います。したがって、空欄にはウが入ります。
d:InterruptedExceptionを宣言する書き方
testとmainでは、InterruptedExceptionを発生させる可能性のある処理を呼び出しています。testはTimerのcloseを呼び出し、closeはthread.joinを実行します。joinは、別のスレッドの終了を待つ処理です。この待機中に割込みが起きるとInterruptedExceptionが発生します。
Javaでは、このような例外(通常の処理とは別に扱うエラーや中断の通知)を、呼出し元で処理するか、メソッド宣言で発生する可能性を示す必要があります。このプログラムでは、メソッド宣言にthrowsを付けています。よって空欄はカです。
testとmainの両方で同じ書き方を使います。mainはtestを呼び出しているため、testで起きる可能性のあるInterruptedExceptionも宣言する必要があります。
e:TimerActionとして渡すインスタンス
createTimerの第2引数には、TimerActionを実装したインスタンスを渡します。TimerTestはTimerActionを実装するクラスなので、testの中でthisを渡せば、現在のTimerTestのインスタンスを渡せます。よって空欄はカです。
longTimerとshortTimerの両方に同じthisを渡します。これにより、どちらのタイマからの通知も、同じTimerTestのonStart、onAlarm、onCancelで受け取れます。
f:shortTimerの終了時にキャンセルする対象
onAlarmでは、引数timerがshortTimerと同じかを調べています。条件が成り立つときにキャンセルするのは、問題文の説明にあるとおりlongTimerです。したがって、呼び出すのはlongTimer.cancel()で、選択肢ではアです。
cancelを呼ぶと、longTimerのWorkerがキャンセル状態になり、スレッドに割込みが通知されます。その後、Workerがループを抜けてonCancelを呼び出します。onCancelをここで直接呼ぶのではなく、cancelを通してタイマの処理をキャンセルする点が大切です。
図1でも、long timerとshort timerの開始後、short timerがonAlarmを呼び出し、その直後にlong timerがonCancelを呼び出しています。遅延時間が短いshortTimerの終了をきっかけに、longTimerがキャンセルされる流れを確認できます。

誤りやすいポイント

  • 残り時間の符号を逆にすること
    終了時刻から現在時刻を引いた値が残り時間です。正の値であれば、まだ終了時刻に達していません。
  • キャンセル後も休止を続けること
    continueではループを続けるため、キャンセルの通知が遅れます。ループを抜けるbreakが必要です。
  • returnでキャンセル処理を終えてしまうこと
    returnを使うと、ループの後にあるonCancelの呼出しに進みません。
  • TimerTestの中でthisが何を指すかを取り違えること
    testの中のthisは、現在のTimerTestのインスタンスです。TimerActionを実装しているので、そのまま引数に渡せます。
  • onAlarmの引数timerをキャンセルすること
    条件が成り立つときのtimerはshortTimerです。キャンセル対象はlongTimerなので、longTimer.cancel()を呼びます。

FAQ

Q: canceledをtrueにするだけではなく、interruptも呼び出すのはなぜですか?
A: canceledは「キャンセルされた」という状態を記録します。一方、interruptは休止中のスレッドを起こすための操作です。状態を記録するだけでは、スレッドがsleepの終了まで休止し続ける可能性があります。
Q: canceledにvolatileを付けるのはなぜですか?
A: canceledは、タイマをキャンセルする側とタイマ処理を実行する側の複数のスレッドから読み書きされます。volatileを付けると、別のスレッドで更新された値を読み取れるようにします。
Q: onCancelをfで直接呼び出さないのはなぜですか?
A: onCancelは、キャンセルが起きたことを通知するためのメソッドです。fではlongTimer.cancel()を呼び、Workerにキャンセル処理をさせます。その結果としてWorkerがonCancelを呼び出します。

関連キーワード: スレッド、インタフェース、volatile、割込み、例外処理

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

 クラスTimerTestに、メソッドlogをオーバロードする次のメソッドを追加した。このメソッドは、タイマの名前の代わりにスレッド名を表示する。
private void log(String msg, long instant) { System.out.println(Thread.currentThread().getName() + ": " + msg + " at " + new Date(instant)); }
 メソッドonAlarm及びonCancelで、このオーバロードしたメソッドlogを呼び出すように変更したところ、図2の実行結果が得られた。図2の3行目及び4行目のに入れる文字列の組合せとして正しい答えを、解答群の中から選べ。ここで、メソッドmainを実行するスレッドの名前はmainとする。また、a〜fには正しい答えが入っているものとする。
基本情報技術者試験(平成24年 午後 問11 図2)
解答群 基本情報技術者試験(平成24年 午後 問11 設問2 解答群)

模範解答

キ

解説

解答の導き方

  1. この設問では、図2の3行目と4行目に表示されるスレッド名を求めます。スレッドとは、プログラムの処理を進める実行の流れのことです。追加されたlogメソッドは、呼び出し元のスレッド名を表示します。
  2. スレッド名は、タイマを作る順番で決まります。testでは、先にlong timerを作り、その後にshort timerを作っています。Timerのコンストラクタは、スレッド名を「Timer-」と連番をつないだ形で付けます。連番は0から始まるので、long timerのスレッド名はTimer-0、short timerのスレッド名はTimer-1です。
  3. 3行目に記録されるonAlarmは、遅延時間が経過したタイマの処理を実行するスレッドから呼び出されます。short timerの遅延時間は2秒で、long timerの4秒より先に終了時刻になります。そのため、short timerのスレッドであるTimer-1がonAlarmを呼び出します。追加されたlogメソッドは呼び出し元のスレッド名を表示するので、g1はTimer-1です。
  4. onAlarmの中では、timerがshortTimerと同じ場合にlongTimer.cancel()を実行します。つまり、Timer-1からlong timerの処理をキャンセルします。ただし、キャンセルを知らせるonCancelは、キャンセルを実行した側ではなく、キャンセルされたタイマの処理を行うスレッドから呼び出されます。
    cancel()は、long timer側の処理に割込みをかけます。割込みとは、実行中の処理に中断を知らせることです。long timer側の処理はキャンセルされたことを確認し、そのスレッドでonCancelを呼び出します。long timerのスレッド名はTimer-0なので、g2はTimer-0です。
以上から、g1がTimer-1、g2がTimer-0となる組合せを選びます。これは解答群のキです。

誤りやすいポイント

  • long timerをキャンセルした処理がTimer-1で実行されたため、onCancelもTimer-1で実行されると思い込まないようにします。onCancelを実行するのは、キャンセルされたlong timer側のスレッドです。
  • スレッド名の連番は、タイマ名や終了順ではなく、スレッドを作る順番で決まります。long timerが先なのでTimer-0です。
  • close()はタイマ処理が終わるのを待つだけです。呼び出したmainのスレッドが、onAlarmやonCancelを実行するわけではありません。

FAQ

Q: onAlarmを呼び出したスレッド名が表示されるのはなぜですか?
A: 追加されたlogメソッドが、呼び出し元のスレッド名を取得して表示するためです。onAlarmは、遅延時間が経過したタイマの処理を実行するスレッドから呼び出されます。
Q: cancel()を呼び出すと、なぜlong timer側のスレッドがonCancelを実行するのですか?
A: cancel()はlong timer側の処理にキャンセルを知らせます。その処理がキャンセルを確認したあと、自分のスレッドでonCancelを呼び出すためです。
Q: canceledにvolatileが付いているのはなぜですか?
A: 複数のスレッドから読み書きされるためです。volatileは、あるスレッドで変更した値を、ほかのスレッドからも確認できるようにするための修飾子です。

関連キーワード: スレッド、割込み、volatile修飾子、メソッドのオーバロード

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

戦国ITクイズ機能

\ せっかくなら /

基本情報技術者を
クイズ形式で学習しませんか?

クイズ画面へ遷移する→

すぐに利用可能!

©︎2026 情報処理技術者試験対策アプリ

このサイトについてブログプライバシーポリシー利用規約特商法表記開発者について