4

I have problem converting my code with the runnable interface to the callable interface in the following code. I need to change, because I need to return a Sting[][] isRs by the threads.

When I just change the interface to callable and chande .run() to .call(), then new Thread(new Worker(startSignal, doneSignal, i)).start(); wont work.

CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(3); // 3 tasks

class Worker implements Runnable {
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
    private final int threadNumber;

    // you can pass additional arguments as well
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal, int threadNumber) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
        this.threadNumber = threadNumber;
    }

    public void run() {
        try {
            startSignal.await();

            if (threadNumber == 1) {
                String[][] isRs = getIS(erg1, erg2, request);
            }

            if (threadNumber == 2) {
                getIW(erg1, erg2, request);
            }

            if (threadNumber == 3) {
                getIN(search_plz, request);
            }

            doneSignal.countDown();
        } catch (InterruptedException ex) {
            System.out.println(ex);
        }
    }
}

// 3 new threads are started
for (int i = 1; i <= 3; i++) {
    new Thread(new Worker(startSignal, doneSignal, i)).start();
}

startSignal.countDown(); // let all threads proceed
try {
    doneSignal.await(); // wait for all to finish
    // all 3 tasks are finished and do whatever you want to do next
} catch (Exception e) {

}
Braj
  • 44,339
  • 5
  • 51
  • 69
user3876178
  • 241
  • 1
  • 4
  • 11

2 Answers2

4

You cannot pass a Callable into a Thread to execute.

Use the ExecutorService to execute the Callable object.

You can give it Callable objects to run using its submit() method:

<T> Future<T> submit(Callable<T> task)

Your class should look like:

class Worker {

    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
    private final int threadNumber;

    Worker(
        CountDownLatch startSignal,
        CountDownLatch doneSignal,
        int threadNumber
    ){

        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
        this.threadNumber = threadNumber;

    }

    public String[][] getSomeStrArrArr() {

        try {

            startSignal.await();

            if (threadNumber == 1) {
                System.out.println("Running thread number 1");
            }

            if (threadNumber == 2) {
                System.out.println("Running thread number 2");
            }

            if (threadNumber == 3) {
                System.out.println("Running thread number 3");
            }

            doneSignal.countDown();

        } catch (InterruptedException ex) {

            System.out.println(
                    "Thread number "+threadNumber+" has been interrupted."
            );

        }

        // replace these 2 lines with the actual code to get the String[][]
        String[][] someStrArrArr = new String[1][1];
        someStrArrArr[0][0] = "Done with thread number "+threadNumber;

        return someStrArrArr;

    }

    public Callable<String[][]> getSomeCallableStrArrArr(){
        return new Callable<String[][]>() {
            public String[][] call() throws Exception {
                return getSomeStrArrArr();
            }
        };
    }

}

And you'd start it like:

    ExecutorService pool = Executors.newFixedThreadPool(3);
    Set<Future<String[][]>> set = new HashSet<Future<String[][]>>();
    CountDownLatch startSignal = new CountDownLatch(1);
    CountDownLatch doneSignal = new CountDownLatch(3);
    for (int i=1;i<=3;i++) {
        Worker worker = new Worker(startSignal,doneSignal,i);
        Callable<String[][]> callable =
                worker.getSomeCallableStrArrArr();
        Future<String[][]> future = pool.submit(callable);
        set.add(future);
    }

And, to get and print the result strings:

    for(Future<String[][]> future : set){
        String[][] result = future.get();
        for (String[] strArr: result){
            for (String str: strArr){
                System.out.println(str);
            }
        }
    }

But this design can be improved. Have a look at the following documentation on Callable to see how it differenciates from Runnable and how you can get advantage from those differences and implent it properly:

Interface Callable

https://blogs.oracle.com/CoreJavaTechTips/entry/get_netbeans_6?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+corejavatechtips+(Core+Java+Technologies+Tech+Tips)

Also check out this link where I've written an example based on your code you can run and fiddle with: http://ideone.com/blUQm0

Robert Harvey
  • 168,684
  • 43
  • 314
  • 475
NotGaeL
  • 7,842
  • 3
  • 35
  • 64
  • This code is very wrong. Your `Worker` does not compile. – Boris the Spider Aug 02 '14 at 11:37
  • "Should look like" is not the same as "Should be". If you want to learn something you must put some effort on it. To make that clearer, I've edited and replaced some ambiguous parts from the snippet. The purpose is for the OP to get the main idea of the required changes in order to use the Callable interface instead of the Runnable; To point him in the right direction, not to do the coding for him. That being said, you are welcomed to provide a better example. – NotGaeL Aug 02 '14 at 12:45
  • Thx for your response, but if i understand your example right, it wont help me. The reason why i use different thread is, that all 3 tasks should be processed at the same time, cause they need some time. in your example they will be processed synchron cause they wait for the return or am i wrong? – user3876178 Aug 02 '14 at 13:32
  • @BoristheSpider As per my understanding provided code by elcodedocle is perfectly fine to explain how to implement the logic.And the final goal is to explain the user so that he get help can fix small compilation issues. – prashant thakre Aug 02 '14 at 13:34
  • ok you are completely right. its parallel. so now i have in set the 3 results of the 3 threads? And how do i get the 3 String[][] Results out of set? – user3876178 Aug 02 '14 at 14:03
  • You can set call() to return String[][] instead of Void. – NotGaeL Aug 02 '14 at 14:42
  • @elcodedocle this is still wrong. And the example is wrong. It uses raw types, which are **extremely** bad practice. – Boris the Spider Aug 02 '14 at 15:38
  • Again, it's just a quick example based on a transliteration on the given code. Again, I've adviced further reading on the topic on my answer: "But this design can be improved". Again, if you've got a better proposition, why not editing my answer or offering one yourself? – NotGaeL Aug 02 '14 at 15:40
  • @elcodedocle because that is not what editing is for. Posting blatantly invalid code and then suggesting "further reading" is unhelpful. Either post correct code or don't post at all. And selling an example that takes a `Callable>` and coerces it into a `Callable` when the `call` method returns `Void` is far from "fully working". – Boris the Spider Aug 02 '14 at 15:42
  • OP wants the code to compile and run without errors using Callable instead of Runnable. I provide that. You complain. I partially agree with you and suggest you provide a better answer. Will you? – NotGaeL Aug 02 '14 at 15:44
  • BTW: I've fixed the issue on my answer; you were right about this (unintentional) missdirection I introduced by copy-pasting from a chunk of code I was using that returned Integer instead of null (Void), but it was already corrected on the example I wrote on http://ideone.com/blUQm0 . I also rewrote my example to return String[][] instead of Void, since it seems to be what the OP wants. – NotGaeL Aug 02 '14 at 16:12
  • Still a rawtype, so still wrong. Less wrong though, admittedly. You should be getting [unsafe operations warnings](http://stackoverflow.com/questions/197986/what-causes-javac-to-issue-the-uses-unchecked-or-unsafe-operations-warning) on compiling this code - listen to the compiler. – Boris the Spider Aug 02 '14 at 16:24
  • You are right again, but that doesn't make my rudimentary example less useful to get a basic clue on how Callable works. I've modified both the example and answer to avoid using raw types (no compiler warnings now), although it's not as clear as it was before. As I've said, I invite you to modify it or provide a better one. – NotGaeL Aug 02 '14 at 17:20
  • Thanks, this is very helpfull: Boris the Spider, Are this compiler warning dangerous? In which situation could they cause an error? @elcodedocl: How do i get one or three normal String[][] out of the Set (the Results of the three threads)? – user3876178 Aug 02 '14 at 17:29
  • Your welcomed. I've updated the example and answer yet again to make it a bit more clear and simple (and without compiler warnings). That's the best I can do, hope you find it useful :-) – NotGaeL Aug 02 '14 at 17:40
  • @elcodedocle : The only thing i dont get ist: Where is the Result. You created the String[][] someStrArrArr. How can i print this after the doneSignal.await();? Thx – user3876178 Aug 02 '14 at 17:50
  • Each `string[][]` result is added to `set`: `set.add(future);` – NotGaeL Aug 02 '14 at 17:56
  • and if there are f.e. 3 String[][][] saved. How to get the 3 normal Strings? String[][] new1 = future.??; String[][] new2 = future.??; String[][] new3 = future.??; – user3876178 Aug 02 '14 at 18:07
  • awesome it works. What about this warning: "The web application [/XXX] appears to have started a thread named [pool-5-thread-3] but has failed to stop it. This is very likely to create a memory leak." Do i need to stop the threads or what does it mean? – user3876178 Aug 03 '14 at 15:16
  • If that happens when you're shutting down tomcat it's somthing common and usually nothing to worry about. (Check out http://www.coderanch.com/t/616315/Tomcat/Memory-Leak-tomcat-due-threads for more info) – NotGaeL Aug 08 '14 at 19:56
1

Once you your class implements callable interface you will have method call and its having return type.

You can use the below code for ExecutorService :-

ExecutorService service =  Executors.newSingleThreadExecutor();
Worker worker= new Worker (tartSignal, doneSignal,threadNumber);
Future<Integer> future = service.submit(worker);
Object result = future.get();

Hope this will help to resolve your issue.

prashant thakre
  • 4,314
  • 2
  • 21
  • 36
  • Thanks. Is Object result the return of call()? How to i get the returned String[][] out of result. Another Problem is, that my start and stopSignal doesnt work anymore – user3876178 Aug 02 '14 at 12:11
  • ah ok start and stopSignal are working, but how to get the return? – user3876178 Aug 02 '14 at 12:19
  • In your worker class after implementing the Callable interface your method signature will change from public void run() to public String[][] Call() and your method will return String[][] this value you will get in String[][] result = future.get(); – prashant thakre Aug 02 '14 at 13:04
  • ah ok. In my codecase, the class worker will called 3 times in 3 threads. Is there only one return from call() or 3, because call gets started 3 times. – user3876178 Aug 02 '14 at 13:24
  • If you want to spawn 3 threads then just change Executors.newSingleThreadExecutor(); to Executors.newFixedThreadPool(3); then the rest three line of code put inside a for loop for three times where threadNumber will change accordingly and you are done , make sure you are storing the output of Call() method in Arraylist or Hashmap.If not clear please update . – prashant thakre Aug 02 '14 at 13:31
  • and i have a general question: i need the 3 tasks in the 3 threads to be processed parallel, cause they need some time, thats my reason for threading. Isnt it right, that they will be processed synchron now, cause they have to wait for the result? – user3876178 Aug 02 '14 at 13:35
  • if you mentioned Executors.newFixedThreadPool(3) it means it will spawn three thread parallel, However i am not pretty sure why you having startSignal.await(); in your worker class. Just execute your code and check the output to know they are working parallel you can put sysout to ensure. – prashant thakre Aug 02 '14 at 13:38
  • your right, startSignal.await is useless. Ok Problem 1 is solved: Object result = future.get(); has to be outside the code for parallel processing. But i just get the result of the last thread – user3876178 Aug 02 '14 at 13:51