Search code examples
javamultithreadingconcurrencyrunnablejava-threads

Some concurrency-design in java


I need to retrieve a huge picture from a server but the server can't do that because the image is too big. I can give "coordinates" so that I can retrieve small parts of that picture. So I split the picture in to 100 tiles and than append 10 tiles to a row and than I append each row. That works well when I do it sequentially. Right now I download 10 tiles -> append them to a row -> download next 10 tiles -> append them to a row -> append the second row to the first one -> download next 10 tiles etc.(simplified):

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);
}

But since the rows are really big it takes very long to append them to each other. While they are being appended, I thought that I could create a thred that downloads the other tiles. And here is the problem. I am not used to program concurrently. I know how it is done technically (implement Runnable etc.) but how should I design it? I had the Idea to run downloadImage(xcoord, ycoord) in another thread but that leads to the question where to put the removeBlackColor(tile) . Also in the thread or after the thread is finished?.. And who should wait for what (with join) ? I hope it was not that confusing. Please let me know if you need more clarification somewhere.


Solution

  • It seems to me you need to still download the rows sequentially and within each row ensure all 10 tiles are download before moving onto the next row.

    Take a look at java.util.concurrent package, specifically the CountDownLatch.

    heres a code snippete. Note: it may not compile correclty but gives an idea.

       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();
    
        }
    
    }