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