イメージ読み込みの処理の流れ

JDK1.02 のアプレットでは、 イメージの読み込みの処理は独立したスレッドによって実行されます。 そのためアニメーションのように読み込みと表示の 同期を取る必要があるプログラムでは注意が必要です。
パラメータで指定された複数のイメージデータを元にして アニメーションを実現することを考えてみましょう。 アニメーションを開始するためには、 すべてのイメージデータのロードが終了していなくてはいけません。 (そうでないと、動きが飛んだり絵が途中で消えたりしてしまいます。) 並列処理でない場合ならば、1つ1つのイメージデータの読み込みを順番に行って、 その後でアニメーションを開始すれば何も問題ありません。 ところがアプレットのプログラムでは、 個々のイメージの読み込みは独立したスレッドによって行われます。 アプレットの表示の処理( update()メソッド )とイメージの読み込み、 そしてアニメーションをコントロールするスレッド、そのどれもが独立した 処理を行います。うまく工夫しないと、イメージが完成しないうちにアニメーション が始まったりしかねません。

さらにややこしいことに、 Imageクラスのオブジェクトが getImage() によって生成されても、 それはすぐに指定された URL のデータを読みにはいきません! より正確に言えば、getImage()によって確かに Image のオブジェクトは生成されるのですが、 その内容が空のままなのです。 実際に読み込みの処理が始まるのは、 drawImage()のような描画命令が最初に呼び出された時です。 このような設計になっているのは、 実際には利用しないデータまで読みにいく無駄を行わないようにするためでしょう。 たとえば、プログラムの中で次のように処理の手順を指定したとします。


1: Image image1 = getImage( .....);
2: Image image2 = getImage( .....);
3: g.drawImage( image1, ..., this );
            :
            :
4: if( ( checkImage( image1, this ) & ALLBITS ) == ALLBITS ) {
5:     g.drawImage( image2, ..., this );
            :
            :
直感的には次のように処理が進むように思えます。
  1. image1 の読み込み。
  2. image2 の読み込み。
  3. image1 の表示。
  4. image1 の読み込み終了の確認。
  5. image2 の表示。
しかし、実際には次のようになります。
  1. image1 のオブジェクトの形式的な生成。
  2. image2 のオブジェクトの形式的な生成。
  3. image1 の読み込みを独立したスレッドが開始。
  4. image1 の読み込み終了の確認。
  5. image2 の読み込みを独立したスレッドが開始。

したがって、 「イメージの読み込みが完全に終わってから表示を行いたい」場合であっても、 常に先に形式的な drawImage() メソッドの呼び出しを行う必要があります。 たとえば、次のような例は一見正しいように思えます。 (実際、コンパイル時のエラーにはなりません。) しかし、イメージはいつまで待ってもロードされず、 何も表示されません!


Image image1 = getImage( .....);
Image image2 = getImage( .....);
            :
            :
if( ( checkImage( image1, this ) & ALLBITS ) == ALLBITS )
     g.drawImage( image1, ..., this );
if( ( checkImage( image2, this ) & ALLBITS ) == ALLBITS )
     g.drawImage( image2, ..., this );
            :
            :