-1

i have a class FeatOrientation and in that class in its constructor i perform two operations each one in a separate thread and i am using CountDownLatch so that, when gaussThread finishes the laplaceThread startes.

and in the main class that has the main method i am using ExecutorService and in the ".runAsync(new FeatOrientRun(bgrMat), featOrientExe);"

in the run method i call "calcFeatOrient" function and in that function i instantiate an object from the FeatOrientation class. and the line

"CompletableFuture.allOf(future0).join();" 

i used it to block the main thread till the two threads in the FeatOrientation class finih and then i do some calculation or display some data as in

"Log.D(TAG, "MainClass", "SmoothedImgList:" + fo.getSmoothedImgList().size());".

the problem is , at run time i receive the output shown below from the console despit the getSmoothedImgList is not empty. I knew that it is not empty by commenting out the following three lines:

    featOrientExe = Executors.newFixedThreadPool(1);
    future0 = CompletableFuture.runAsync(new FeatOrientRun(bgrMat), featOrientExe);

CompletableFuture.allOf(future0).join();//blocks the main thread till  future0, and future1 finishes

    featOrientExe.shutdown();

and i instantiated an object from the FeatOrientation class in the main method and then , made the main thread to sleep for 7 seconds and after the 7 seconds, i called the following lines

    Log.D(TAG, "MainClass", "SmoothedImgList:" + fo.getSmoothedImgList().size());
    Log.D(TAG, "MainClass", "SubSampledImgList:" + fo.getSubSampledImgList().size());

    for (int i = 0; i < fo.getSmoothedImgList().size(); i++) {
        ImageUtils.showMat(fo.getSmoothedImgList().get(i), "SmoothedImgList_" + i);
    }
    for (int i = 0; i < fo.getSubSampledImgList().size(); i++) {
        //Mat laplaceImg = SysUtils.applyLaplac(fo.getSubSampledImgList().get(i));
        //ImageUtils.showMat(laplaceImg, "getSubSampledImgList" + i);
    }

and i received outout.

please let ma know what i am doing wrong with the ExecutorService, and why the approach i am following in the below posted code does not work desoite i wait till the FeatOrientation class finish it works.

console out put:

1: Error: FeatOrientation -> getSmoothedImgList: smoothedImgList is empty
Exception in thread "main" java.lang.NullPointerException
at com.example.featorientation_00.MainClass.main(MainClass.java:39)

main class:

    public static void main(String[] args) {
    MatFactory matFactory = new MatFactory();
    FilePathUtils.addInputPath(path_Obj);
    Mat bgrMat = matFactory.newMat(FilePathUtils.getInputFileFullPathList().get(0));

    featOrientExe = Executors.newFixedThreadPool(1);
    future0 = CompletableFuture.runAsync(new FeatOrientRun(bgrMat), featOrientExe);
    CompletableFuture.allOf(future0).join();//blocks the main thread till future0, and future1 finishes
    featOrientExe.shutdown();

    Log.D(TAG, "MainClass", "SmoothedImgList:" + fo.getSmoothedImgList().size());
    Log.D(TAG, "MainClass", "SubSampledImgList:" + fo.getSubSampledImgList().size());

    for (int i = 0; i < fo.getSmoothedImgList().size(); i++) {
        ImageUtils.showMat(fo.getSmoothedImgList().get(i), "SmoothedImgList_" + i);
    }
    for (int i = 0; i < fo.getSubSampledImgList().size(); i++) {
        //Mat laplaceImg = SysUtils.applyLaplac(fo.getSubSampledImgList().get(i));
        //ImageUtils.showMat(laplaceImg, "getSubSampledImgList" + i);
    }


}

static class FeatOrientRun implements Runnable {

    private Mat bgrMat;
    public FeatOrientRun(Mat bgrMat) {
        // TODO Auto-generated constructor stub
        this.bgrMat = bgrMat;
    }

    public void run() {
        // TODO Auto-generated method stub
        calcFeatOrient(this.bgrMat);
    }
}

public static void calcFeatOrient(Mat bgrMat) {
    // TODO Auto-generated method stub
    fo = new FeatOrientation(bgrMat);
}

FeatOrientation class:

    public FeatOrientation(Mat bgrMat) {
    // TODO Auto-generated constructor stub
    this.origBGRImgList = new ArrayList<Mat>();
    this.origGSImgList = new ArrayList<Mat>();
    this.smoothedImgList = new ArrayList<Mat>();
    this.downSampledImgList = new ArrayList<Mat>();
    this.laplaceImgList = new ArrayList<Mat>();
    this.latch = new CountDownLatch(1);

    if (bgrMat != null) {
        if (!bgrMat.empty()) {
            if (bgrMat.channels() == 3) {
                if ( (bgrMat.size().width >= SysConsts.MIN_IMG_WIDTH) && (bgrMat.size().height >= SysConsts.MIN_IMG_HEIGHT) ) {

                    this.bgrMat = bgrMat;

                    this.gaussThread = new Thread(new GaussRun(this.bgrMat, this.latch), "GAUSSIAN_THREAD");
                    this.laplaceThread = new Thread(new LaplaceRun(this.latch), "GAUSSIAN_THREAD");
                    this.gaussThread.start();
                    this.laplaceThread.start();

                } else {
                    Log.E(TAG, "FeatOrientation", "the Mat you passed to the constructor has size: " + this.bgrMat.size() + 
                            " the minimum width must = " + SysConsts.MIN_IMG_WIDTH + 
                            " and the maximum height must = " + SysConsts.MIN_IMG_HEIGHT);
                }
            } else {
                Log.E(TAG, "FeatOrientation", "BGR mat passed to the constructor does not has 3 channels.");
            }
        } else {
            Log.E(TAG, "FeatOrientation", "BGR mat passed to the constructor is empty");
        }
    } else {
        Log.E(TAG, "FeatOrientation", "the BGR mat you passed to the constructor is null");
    }
}

class GaussRun implements Runnable {

    private Mat bgrMat;
    private CountDownLatch latch;

    public GaussRun(Mat bgrMat, CountDownLatch latch) {
        // TODO Auto-generated constructor stub
        this.bgrMat = bgrMat;
        this.latch = latch;
    }

    public void run() {
        // TODO Auto-generated method stub
        applyGaussianPyr(this.bgrMat);
        this.latch.countDown();
    }

}

class LaplaceRun implements Runnable {

    private CountDownLatch latch;

    public LaplaceRun(CountDownLatch latch) {
        // TODO Auto-generated constructor stub
        this.latch = latch;
    }
    public void run() {
        // TODO Auto-generated method stub
        try {
            this.latch.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        applyLaplacianPyr();
    }

}
Amrmsmb
  • 1
  • 27
  • 104
  • 226

1 Answers1

1

Your collection is not thread safe so while the task may have finished, this doesn't mean the result is visible to another thread.

You could use a thread safe collection, but I prefer to return the results via Future<List<X>> and call list = future.get() This will both wait for the result and ensure it is passed in a thread safe manner regardless of which collection you use.

I assume this is just an example.
Running threads only makes sense if you have independent tasks (plural) to perform. It makes no sense to start one thread and wait for it's response, you may as well do the work in the current thread as it will be simpler and faster.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • thanks for your answer. actually i am not expecting results from CompletableFuture.runAsync(new FeatOrientRun(bgrMat), featOrientExe); , i just want to wait till it finishes, so that i can do some operations – Amrmsmb May 08 '15 at 10:10
  • @user2121 as long as you understand that even when the task does complete, this doesn't mean you can use the results of that task in another thread unless you consider thread safety. – Peter Lawrey May 08 '15 at 10:13
  • @user2121, Peter's point is that, at a time only you are performing only one task, so why not do all of that in a single thread, instead of spawning multiple threads to do the tasks one after the other. – Kishore May 08 '15 at 10:15