- PR -

java.util.TimerTask が state を持つことをどうやって分かるのか?

1
投票結果総投票数:8
ソースコードを見ろ 7 87.50%
javadocが不完全なのだ 1 12.50%
API は使ってみないことには分からないものなのだ 0 0.00%
  • 投票は恣意的に行われます。統計的な調査と異なり、投票データの正確性や標本の代表性は保証されません。
  • 投票結果の正当性や公平性について、@ITは一切保証も関与もいたしません。
投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-03-21 21:12
TimerTask と Timer の仕様、
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/TimerTask.html
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/Timer.html
を見て、たとえば、つぎのようなコーディングをしましたとします。
目論見は main の実行開始時刻(T)の1秒後(T+1秒)に Hello を、2秒後(T+2秒)にも Hello を表示するためです。
コード:
import java.util.Timer;
import java.util.TimerTask;

public class Hoge {

	public static class MyTask extends TimerTask {

		@Override
		public void run() {
			System.out.println("Hello.");
		}
	}
	public static void main(String[] args) {
		TimerTask task = new MyTask();
		Timer timer = new Timer();
		timer.schedule(task, 1000L);
		timer.schedule(task, 2000L); // この行で java.lang.IllegalStateException: Task already scheduled or cancelled
		
		try {
			Thread.sleep(60 * 1000L);
		} catch (InterruptedException ex) {
			throw new RuntimeException(ex);
		}
	}
}


しかし、2回目の schedule の呼び出しで IllegalStateException が発生してしまいます。
上記の javadoc を見ても、この理由が分かりません。TimerTask 内部のソースコードを見ると、
コード:
    int state = VIRGIN;


という state を持っていることから、なんとなく理由が分かります。

結局はソースコードを見ない限り、API を使用するために必要な仕様は分からないということなのでしょうか?それとも私のアプローチのしかたが正しくなかったのでしょうか?

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-03-21 21:42
一応、Timer#schedule(TimerTask, long)の例外欄に
「タスクがすでにスケジュールされたか取り消された場合」
とあるので、同じタスクを複数回スケジュールできない
仕様であることを推測できなくもないですね。

あとは、TimerTask側にcancel()メソッドを持っていますが、
スケジュールを複数回行えたとすると、いつスケジュールした
ものなのか特定できなくなるため、仕様的に破綻してしまいます。

表現的にも意味的にもわかりやすいかは別にして、
繰り返し実行をサポートするための仕様なのでしょう。
kuma
大ベテラン
会議室デビュー日: 2004/02/25
投稿数: 110
投稿日時: 2007-03-21 23:38
stateを持つかどうかは別にして
Timer#purge
からTimer:TimerTaskが1:nであることは解り
Timer#schedule
のIllegalStateExceptionの説明の「すでに」の部分から推測できそうな気もしますが
解り難いといえば、そうかもしれないですね。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2007-03-21 23:51
英語版のAPIドキュメントを読むと自明だったりします。

引用:

A task that can be scheduled for one-time or repeated execution by a Timer.



「A task」と「a Timer」ですから、1対1であることが明白です。
sawat
大ベテラン
会議室デビュー日: 2006/08/02
投稿数: 112
投稿日時: 2007-03-22 10:30
余談ですが、j2se5以降は java.util.Timer よりも
java.util.concurrent.ScheduledExecutorService を使うほうが推奨されます。

ScheduledExecutorServiceの場合は、RunnableまたはCallableを登録して、ScheduledFutureを受け取り、ScheduledFutureに対してキャンセルを行うので、RunnableやCallableは繰り返し登録することができます。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-03-24 17:20
引用:

スフレさんの書き込み (2007-03-21 23:51) より:
「A task」と「a Timer」ですから、1対1であることが明白です。


なるほど。英語の原文から欠落している情報がないかにも注意して、文章を深く読む必要がある、ということですね。

なお、今回の質問に至ったのは、TimerTask クラスの state というフィールドが隠蔽されてしまっている(パッケージアクセスになっている)が、それにアクセスするメソッドも隠蔽されてしまっている、というのが解読を困難にしている元だと思ったからです。Timer と TimerTask の間では state を隠蔽していないのに、Timer と TimerTask の外側からは state が見えないようになっている、という作りは、なんだか違和感を感じます。
要は、パッケージアクセスだから見せない、というのが良い作りなのか、というのが疑問なのです。もっとも、Java API のソースコードを見ると、いたるところにパッケージアクセスのフィールドがあります。

TimerTask クラスに戻りますが、この cancel メソッドの実装を見ると、メソッドの戻り値は state フィールドに依存しています。だったら、state フィールドの getter を public で持っていても良いのではないでしょうか。state のすべての状態をあらわにせずとも、
コード:
    public boolean isScheduled() {
        return (state == SCHEDULED);
    }


のようなメソッドは持っているべきでは、と思います。

引用:

sawatさんの書き込み (2007-03-22 10:30) より:
余談ですが、j2se5以降は java.util.Timer よりも
java.util.concurrent.ScheduledExecutorService を使うほうが推奨されます。


このクラスの存在を知りませんでした。
こっちのほうがシンプルで良さそうですね。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
1

スキルアップ/キャリアアップ(JOB@IT)