-1

サーバーから巨大な画像を取得する必要がありますが、画像が大きすぎるため、サーバーはそれを実行できません。その写真の小さな部分を取得できるように、「座標」を与えることができます。そのため、画像を 100 個のタイルに分割し、10 個のタイルを行に追加し、各行を追加します。順番に行うとうまくいきます。現在、10 個のタイルをダウンロード -> それらを行に追加 -> 次の 10 個のタイルをダウンロード -> 行に追加 -> 2 行目を最初の行に追加 -> 次の 10 個のタイルをダウンロードなど (簡略化):

public static void downloadWholeImage(){
   int xcoord=0;
   int ycoord=0;
   //outer loop for each row
   for(int i = 0; i<10; i++){
      //all tiles of a row are stored here
      BufferedImage[] tilesForRow = new BufferedImage[10];
      //inner loop for each tile of a row
      for(int j = 0; j<10; j++){
         //downloads the image
         BufferedImage tile = downloadImage(xcoord,ycoord);
         //removes all black pixels of the image
         BufferedImage[j] = removeBlackColor(tile);
         //increments xcoord so the next tile
         xcoord++;
      }
      //each row gets appended on top of the first row
      if(i==0){
         BufferedImage firstRow = appendTilesToRow(tilesForRow)
      } else{
         BufferedImage actualRow = appendTilesToRow(tilesForRow)
      }

      firstRow = appendActualToFirst(firstRow, actualRow); 
      //incrementing ycoord for next tile
      ycoord++;
   }
   writeImage(path,firstRow);
}

しかし、行が非常に大きいため、それらを互いに追加するには非常に時間がかかります。それらが追加されている間、他のタイルをダウンロードするスレッドを作成できると思いました。そして、ここに問題があります。私は並行してプログラミングすることに慣れていません。技術的にどのように行われるか (Runnable の実装など) は知っていますが、どのように設計すればよいですか? downloadImage(xcoord, ycoord)別のスレッドで実行するというアイデアがありましたが、 removeBlackColor(tile). また、スレッド内またはスレッドが終了した後?..そして、誰が何を(結合して)待つべきですか? それほど混乱していなかったことを願っています。どこかでさらに説明が必要な場合はお知らせください。

4

4 に答える 4

2

次のように実行できます。ダウンロード操作ごとに新しいスレッドを作成します。ダウンロードは run() メソッドで行われます。その後、各スレッドは、次のダウンロードが join() で完了するまで待機し、タイルを追加します。

同様のアプローチを使用して、各行をダウンロードして追加できます。

public class Download extends Thread {
    public static void main(String[] args) throws InterruptedException {
        Download[] download = new Download[10];
        for (int i = 0; i < 10; i++) {
            download[i] = (new Download(i));
            download[i].start();
        }
        for(int i = 0; i < 10; i++) {
            (download[i]).join();
            append(i);
        }
    }
    int val;
    Download(int val) {
        this.val = val;
    }
    @Override
    public void run() {
            System.out.println("Downloading tile " + val);
    }

編集

Runnable を実装したい場合、構文は次のようになります。

public class Download implements Runnable {
...
        Thread[] download = new Thread[10];
        for (int i = 0; i < 10; i++) {
            download[i] = new Thread(new Download(i));

これは最初の例とまったく同じように機能するため、Thread を拡張するか Runnable を実装するかは好みの問題です。

于 2015-03-03T12:40:09.443 に答える
1

タイルが追加されている間に、他のタイルを非同期でダウンロードしたいようです。

そのため、あなたの答えはここにあるようです: 真に非同期の Java スレッドを実装するにはどうすればよいですか?

注意: 待つ必要はありません。別のプロセスが実行されている間に、1 つのプロセスが非同期で終了するようにします。

EDIT:同期ブロックを使用して、ダウンロードが成功するたびに特定の追加を実行する必要があることを定義することもできます。

于 2015-03-03T12:12:09.837 に答える
1

行を順番にダウンロードし、各行内で次の行に移動する前に10個のタイルすべてがダウンロードされるようにする必要があるようです。

パッケージjava.util.concurrent、特にCountDownLatch.

コードスニペットをここに示します。注:正しくコンパイルされない場合がありますが、アイデアは得られます。

   public static void main(String[] args) throws InterruptedException {

    CountDownLatch countLatch = new CountDownLatch(10);
    ExecutorService threadPool = Executors.newFixedThreadPool(10);
    ArrayList<SampleImageDownload> list = new ArrayList<SampleImageDownload>();
    int row =1;

    while (row <=10) {
        int tileno = 1;
        while(tileno <=10) {
         SampleImageDownload sample = new SampleImageDownload(countLatch, tileno);
         list.add(sample);
         threadPool.submit(sample); 
         tileno++;

        } 
            row++;
            countLatch.await(); // wait for all 10 tiles to download.
        //apendline
    }




}


class SampleImageDownload implements Runnable {

    int tileno;
    private CountDownLatch countLatch = null;
    BufferedImage tile = null;


    public SampleImageDownload(CountDownLatch countLatch, int tileno) {
        super();
        this.countLatch = countLatch;
        this.tileno = tileno;
    }


    @Override
    public void run() {

        // download and removeBlacktile
        // tile is ready
        countLatch.countDown();

    }

}
于 2015-03-03T13:01:00.850 に答える
0

可能性の 1 つは、N 個のダウンロード スレッドを実行するメイン スレッドを作成することです。各ダウンロード スレッドはサーバーからタイルを取得し、全体像のフラグメントをタイルと交換できます。スワッピングに関しては、「衝突」しないように、それぞれが全体像の独自の部分で動作する限り、おそらく多くのスレッドで同時に実行できます。1 つのスレッドが 0 から X までのインデックスで動作し、もう 1 つのスレッドが配列の末尾までの X+1 で動作する配列を考えてみてください。それが機能するには、事前に全体像のサイズを知って初期化する必要があります。しかし、あなたはすでにそうしていると思います。メインスレッドは、すべての小さなスレッドが終了するのを待つだけで、ジョブが完了したことを意味します。

于 2015-03-03T12:18:41.437 に答える