2011-11-10 11 views
1

複数のスレッドを使用してファイルをサーバーにアップロードしています。 JavaアプレットはUIを表示します。最初にThreadPoolExecutor &を使用して5つのスレッドを開始し、5つのファイルを割り当てます。各アップロードの後、私はサーバーから通知を受け取ります。スレッドが実行を完了すると、すべてのファイルがサーバーにアップロードされるまで、別の新しいスレッドにファイルが割り当てられます。ThreadPoolExecutorの実装上の問題

基本的なコードの構造を次のように

i>のアップロード機能を処理する責任があるJavaアプレットから呼び出されるメソッドstartUpload()。

class Upload extends Runnable{ 


............................... 
.............................. 

public void startUpload() { 

............................... //other initialisations done 

    int waitTime = 500; 

    Random random = new Random(); 

    ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300)); 

    while (it.hasNext()) { 

       int time = random.nextInt(1000); 
       waitTime += time; 
       newFile = new File((String) it.next()); 

       executor.execute(new Runnable() { 

        @Override 
        public void run() { 

         try{ 
         Thread.sleep(wait); 
         } 
         catch(Exception e){ 
         } 
         processFile1(newFile); 
        } 
       }); 

      } 
      try { 
       Thread.sleep(waitTime); 
       executor.shutdown(); 
       executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS); 

      } catch (Exception e) { 
      } 

    } 

}

私は現在直面しています問題。

i> UIはすべてのファイルがアップロードされたときに最後に更新されます。中間段階では、UIはハング状態にあります。 EDTがブロックされた状態になるようです。

同じ機能を実装するために、スレッドクラスnotify/sleepを使用していたときに、UIレンダリングと同じコードが正常に機能していました。私は、Javaのバージョン5.0からマルチスレッドを実装するためのより良い方法をブログ/記事で見たので、コードをThreadPoolExecutorに変更しました。上記のコードからwait()をすべて削除すると、サイズが1KB(テスト目的)の複数のファイルをアップロードしているときに、ThreadPoolExecutorに気づいたもう1つの点は、次の行が新しいファイルを割り当てます。常に同じファイルが複数のスレッドによって毎回アップロードされています。

newFile = new File((String)it.next());

しかし、run()を使ってsleep()を追加すると、複数のスレッドが異なるファイルをサーバーにアップロードします。

上記のコードで実装上の問題はありますか?

答えて

2

問題1:newFileは、ローカル変数の代わりに(static?)フィールドです。

newFileのローカルキャプチャがループごとに異なることを確認してください。このように、それはより多くのようになります。

while(it.hasNext()) { 
    final File newFile = new File((String) it.next()); 
    executor.execute(new Runnable() { 
    @Override 
    public void run() { 
     processFile1(newFile); // Local only to this iteration of the loop. 
    } 
    } 
} 

あなたのコードは、すべてのRunnableインスタンスに包まれています。あなたは、このスレッドが呼び出されたスレッドを教えてください。それがEDT上にあれば、UIがロックアップする理由を説明します。

小さな問題は、イテレータのジェネリックの欠如です。理論的には、文字列のコレクションを反復処理する必要があります。

Collection<String> listOfFiles = ... 

Iterator<String> it = listOfFiles.iterator(); 

while(it.hasNext()) { 
    String filename = it.next(); // No cast necessary 
} 
1

EDTスレッドをブロックしているためUIがハングしています。このコードは、犯人です:

try { 
     Thread.sleep(waitTime); 
     executor.shutdown(); 
     executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS); 

    } catch (Exception e) { 
    } 

ExecutorServiceのアイデアは、あなたが初期化時に一度、それを作成し、プログラムを終了する準備ができるまでそれをシャットダウンすることはありませんということです。このためイディオムは次のようになります。

ExecutorService executor = Executors.newFixedThreadPool(5); 
Runtime.getRuntime().addShutdownHook(new Thread() { 
    public void run() { 
     executor.shutdown(); 
    } 
}); 

@ Bringer128述べたように、第二の問題は、あなたは、静的またはメンバ変数の値を変更し、新しい場所へFileの参照を代入していないことに起因します。コードが正しければ、newFilefinal File newFileと宣言されていると予想されます。これは、最終的なローカル変数が内部クラスで参照されない可能性があるためです。

+0

ご返信ありがとうございます。 Fileをfinalおよびそのローカル変数に変更しました。私が得ている問題は、2回のスレッドが同じファイルをアップロードしようとしている場合があります(3回に1回)、問題は基本的にスレッドの同期です。サーバーのログから、私は2つのスレッドが同じファイルをアップロードしようとしていることを知りました。そのため、その要求は重複しています。それに関する提案はありますか? – chiranjib

+0

@chiranjib私が提案した変更を試してください。 'newFile'が私のコードのようなローカル変数なら、エグゼキュータは正しい値を得ます。エグゼキュータがいつnewFileにアクセスするかは分からないので、メインスレッドがそれをいつ更新するかによって、同じファイルか別のファイルを取得することができます。 – Bringer128

関連する問題