トップページ⇒tech
20コメント14KB

★JAVAアプレット★複数のスレッド

■ このスレッドは過去ログ倉庫に格納されています
0001JAVA次郎 NGNG
アプレットでRunnableインターフェイスを用いて、複数個のスレッドを
立ち上げるにはどうしたらいいのでしょう?
各スレッドには、描画とhttp経由でのデータ取得をさせたいと考えて
います。かなり切羽詰まっています〜〜〜。
0002名無しさん@お腹いっぱい。 NGNG
つまりJAVA次郎さんが仰りたいことというのは――

Runnableインターフェイスを実装(implements)したクラスは,
run()メソッドを一つしか持つことができない。
これでは「アプレットは複数のスレッドを作れない」ということではないだろうか?

――ということだと思います。

ところで「スレッドになるクラス」というのは,Threadクラスを継承(extends)したクラス,
あるいはRunnableインターフェイスを実装したクラスのいずれかです(後者の方が一般的です)。

ですから,「描画を受け持つクラス」と「http経由でデータを取得するクラス」を別にして
それぞれにRunnableインターフェイスを実装すればよいだけのことです。

クラスをわざわざ作るのが嫌(クラス名を考えるのが面倒くさい)というときは,
匿名クラスを使うと便利です。

――コード例――
Thread threadA = new Thread(new Runnable() {
  public void run() {
    while (true) {
      System.out.println("Running Thread A");
    }
  }
});
Thread threadB = new Thread(new Runnable() {
  public void run() {
    while (true) {
      System.out.println("Running Thread B");
    }
  }
});
threadA.start();
threadB.start();
0003JAVA次郎 NGNG
レスありがとうございます。教えていただいた方法で、複数の
スレッドを立ち上げることに成功しました。しかし
ここで新たな問題が・・・・・・!

再描画のスレッドで
Thread.sleep(20);
データ取得のスレッドで
Thread.sleep(3000);
と設定しているのですが、どうしても3秒おきにやってくるデータ
取得の際に再描画の処理が遅くなってしまいます。
再描画のスレッドではダブルバッファを用いて、テロップの様に
文字列を右から左へ常に流しておかなければならないのですが、
データ取得のスレッドが来ると、カクカクした動きになるのです。
テロップをスムーズに流しつつ、3秒おきのデータ取得を行う
いい解決法はありますでしょうか?
00042 NGNG
>3
実際のコードを見ないと,どこがボトルネックなのか分からない
というのが本音です。しかしながら,

>描画のスレッドで
>Thread.sleep(20);
>データ取得のスレッドで
>Thread.sleep(3000);
>と設定しているのですが

再描画の時間間隔が短すぎると思います。20msec毎ということは,
1秒間に50回も再描画していることになります(50フレーム/秒)。
テレビ放送(NTSC方式)が30フレーム/秒,映画が25フレーム/秒ですから,
テロップの類は15フレーム/秒程度で十分だと思います。

#再描画の間隔を長くするとそれだけ処理が軽くなります。
00052さんではありませんが NGNG
>>3
私が手に負えるレベルならお助けしたいところですが……。
ちょっと質問が漠然としているので答えられないと思います。
せめて
・httpで受信するデータはどのくらいのサイズか
・データ受信の処理はどのようにしているか
が最低解らないと、
どうしようもないのか、改善の余地があるのかを判断のしようがないです。
00065 NGNG
あ、かぶった……。(恥)
0007名無しさん@お腹いっぱい。 NGNG
ちょっとスレッドの話しに戻ってしまうのですが、

>>2
>>あるいはRunnableインターフェイスを実装したクラスのいずれかです(後者の方が一般的です)。

Runnableインターフェースを使えば自分自身をスレッド化でき、余計なclassファイルを作らずに
済むので確かに良く使われていますが1さんが悩んでたように複数個のスレッドを作成したくなっ
た時に困ります。

将来の拡張を考えた場合Runnableは使わない方が良いと思います。

あと、例で出してる無名クラスでRunnableを継承した無名クラスを作成しているようですが、
これは必要無いのでは?(Threadを継承した無名クラスで問題無いはずだと思います)
0008JAVA次郎 NGNG
あれからいろいろと改善を試みたのですが、どうも原因が別のところに
あるように思います。
アプレットを開始してしばらく(5分くらい)すると、次第に処理が重く
なっていきます。CPUの使用率、メモリ使用量ともに、右肩上がりです。
Graphicsオブジェクトをdisposeし、オブジェクトにnullをつっこみ
System.gc()を実行して少しでもリソースを開放するようにしているのですが、
全く効果がみられないようです・・・・
0009名無しさん@お腹いっぱい。 NGNG
スレッドが増えまくってるとか?
0010JAVA次郎 NGNG
スレッドをnewする処理は全部initの中でやってるので、
増えまくってるってこともなさそうです・・
00115 NGNG
ソースを見なきゃ何とも言えないですが。

処理の重くなりかたが穏やかなので、Thread内でドカドカインスタンスを作りまくっているため、
とかそういうのじゃなさそうですね。

いずれにせよ、お答えするには情報少なすぎです。
0012JAVA次郎 NGNG
スレッドの部分は2さんのアドバイスの様にしてみました。
アプレットのサイズは横800、縦600で、テロップを流す時の
1番目のスレッドで全画面を再描画しています。
2番目と3番目のスレッドはHTTPでのデータ取得のためのスレッドで、
それぞれ256文字程度の文字列を取得します。
そして、2番目のスレッドで取得した文字列をテロップで画面上に流します。

oThreadA = new Thread(new Runnable(){
public void run(){
while(true){
テロップを流す処理
repaint();
try{
Thread.sleep( 40 );
}
catch(InterruptedException e){}
}
}
});
oThreadA.start();

oThreadB = new Thread(new Runnable(){
public void run(){
while(true){
if (stockquery != null) {
try {
HTTP経由で文字列データ取得
}
catch (java.rmi.RemoteException e) {
System.out.println(e);
}
try{
Thread.sleep(20000);
}
catch(InterruptedException e){}
}
}
}
});
oThreadB.start();

oThreadC = new Thread(new Runnable(){
public void run(){
while (true){
if(stockquery != null){
try{
HTTP経由で文字列データ取得
}
catch(java.rmi.RemoteException e){}
try{
Thread.sleep(3000);
}
catch(InterruptedException e){}
}
}
}
});
oThreadC.start();
00135 NGNG
>>12のソースをほぼそのまま(スレッドの内部処理をSystem.out.printlnに変更しただけ)
IE5上で動かしてみた限りでは、特に問題なく動いていますね。
ただ、気になるのは、ThreadBとThreadCはいったいどういう関係なんでしょう?
この二つのスレッドのカラミが怪しいと見ましたが、如何でしょう?
例えば、両方同じクラスインスタンス「stockquery」を参照してますね。
ThreadBとThreadCの内部でこのインスタンスに対する処理がバッティングしたりはしていないでしょうか。

それ以外にも、密接に関わり合う複数のスレッドを動かした場合には予想もしない動作をすることがありますので気をつけてみてください。
0014名無しさん@お腹いっぱい。 NGNG
描画近辺の処理が怪しいと思います。
一度に描画する文字列の長さはどれくらいですか。
フォントサイズを400ポイント程度にしても正常に動作しますか。

つまり
String str = "..."; // 256文字分の文字列
g.drawString(str@` 0@` 0);
のように,スクリーンサイズをはみ出すくらい長い文字列を描画していませんか。
00155 NGNG
今ふと思ったんですが、もしかして、描画の際ダブルバッファリングしてますか?
だとしたら、描画毎に裏画面作成したりはしてませんか?
ごく基本的なことなんですが、一応確認を。
こちらを参考に。↓
ttp://www.mi-ra-i.com/JinSato/Java/Numon/du00.html

>>14さん
>スクリーンサイズをはみ出すくらい長い文字列を描画
した場合、メモリのリークかなにかが起こるのでしょうか。
私はそういう話は聞いたことがないので、よろしければもう少し詳しくご教授ください。
ちょっと試して見た限りでは、そういう現象は確認できなかったのですが……。
001614 NGNG
>>15
すみません。誤解させてしまったかもしれません。
メモリリークなどの致命的な問題は起こりません(実際に実験したことがあります)。
領域判定の処理が嵩んで,スループットが低下するだけです。
00175 NGNG
ああなるほど、了解しました。>>16さん
そう言われてみれば私もマーキーを作成したときにその現象に出くわしたことがあります。
説明ありがとうございます。

ところで今気付いたんですが、JAVA太郎さんの>>8の書き込み。
>Graphicsオブジェクトをdisposeし、オブジェクトにnullをつっこみ
って書いてらっしゃいますよね。
ってことは>>15で指摘したように
「Graphicsオブジェクトのnew、disposeを毎回行っている」
んじゃないのかなぁと思いました。
(それ以外にGraphicsオブジェクトを意識的に(つまり頻繁に)disposeする
 必要があるケースというのは思いつかないので)

いかがでしょうか?
00185 NGNG
>>17
>JAVA太郎さん
じゃなくて
JAVA次郎さん
でした。失礼しました……。

鬱だ氏脳……。
0019JAVA次郎 NGNG
>>17さん
おっしゃる通り、毎回裏画面を作成していました・・・
これはダサい処理ですね。ご指摘ありがとうございます。
5さんのリンク先にあるようにinitの中で実行すれば
良いのかもしれません。早速試してみます。他にもそういう
毎回行う必要のない処理がまだ出てくるかも知れませんので、
徹底的に洗い出してみます!
今日はテロップで流す文字列をキューに格納して見たのですが、
なぜか時間が経つと共にリソースが減っていくという現象がなくなりました。
70%くらいでずっと安定しています。800x600サイズのアプレット
でのリソースって、こんなものなのでしょうか?
ちょっと土日はテストできない状態なので、また追って報告します。

>>5さん
太郎でも次郎でもお好きなほうでドーゾ(笑)
0020名無しさん@お腹いっぱい。 NGNG
>19
キューに格納する文字がループになってて
最適化掛かってるとか。。。

テロップって、同じ文字列流すだけならラウンドロビンで
配列まわすようにすればいいのかな?
■ このスレッドは過去ログ倉庫に格納されています