0

I posted a question on about brute forcingCodeReview, and a good expert helped me out by suggesting I should use multithreading to improve the speed of my program. The code he gave was good, improved the speed but was still slow for me, so I went to research more about multithreading and found good articles and examples. I copied one example that I understood and made few changes to fit my need. The code works perfectly till I read deep about multithreading and came across invokeAny(), I tried to implement it and thus the beginning of my headache for some unknown reason it's giving me errors. I just want to be able to get the first task that find the resolved ID using invokeAny, since the program is fast now.

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.UnsupportedOperationException: Not supported yet.
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at java.base/java.util.concurrent.AbstractExecutorService.doInvokeAny(AbstractExecutorService.java:199)
at java.base/java.util.concurrent.AbstractExecutorService.invokeAny(AbstractExecutorService.java:220)
at pait.SiimpleeThreadPool.main(SiimpleeThreadPool.java:31)
Caused by: java.lang.UnsupportedOperationException: Not supported yet.
at pait.WorkerThread.call(WorkerThread.java:73)
at pait.WorkerThread.call(WorkerThread.java:15)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.awt.Label;
import java.util.Random;
import java.util.concurrent.Callable;
public class SimpleThreadPool {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        int s = 135000000;
        int e = 200000000;
        List<Callable<String>> callList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            Callable worker = new WorkerThread("" + i, s, e);
            callList.add(worker);
            s = s + 15520000;
        }
        String result = executor.invokeAny(callList);
        System.out.println(result);
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        System.out.println("Finished all threads");
    }

}

public class WorkerThread implements Callable {

    private final  String command;
    private final int start;
    private final int end;
    private final Label lb = new Label();

    public WorkerThread(String s, int start, int end) {
        this.command = s;
        this.start = start;
        this.end = end;
    }

    public void run() {
        processCommand(start, end);

    }

    private void processCommand(int start, int end) {
        for (int i = start; i < end; i++) {
            Random rand= new Random(i);
            long pair = rand.nextInt();
            if (pair == 739619665) {
                System.out.println(start + "     " + end + "        Executing Task inside : " + Thread.currentThread().getName());
                System.out.println(i);
                lb.setText("Stop");
                break;
            }
        }
    }

    ;

    @Override
    public String call() throws Exception {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public String toString() {
        return this.command;
    }

}
Slaw
  • 37,820
  • 8
  • 53
  • 80
Hither Joe
  • 117
  • 2
  • 9

1 Answers1

1

Why an UnsupportedOperationException?

Your WorkerThread class implements the Callable interface, which is:

A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call.

APIs that use implementations of Callable, such as ExecutorService#invokeAny(Collection), will invoke the call method which means the actual work needs to be implemented inside said call method. However, your code is the following:

@Override
public String call() throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

This is why you're getting an UnsupportedOperationException, because that's exactly what the method is programed to do. To fix this you need to simply implement the method properly. You also have:

public void run() {
    processCommand(start, end);

}

Which makes me think you either got confused between the Runnable and Callable interfaces or the WorkerThread class used to implement Runnable and you forgot to update the code completely when switching to Callable. Assuming processCommand is the actual work of the task, your call method should look something like:

@Override
public String call() throws Exception {
    processCommand(start, end);
    return "I don't know what's supposed to be returned";
}

And you can remove the run method.


Awaiting Termination

You shouldn't spin waiting for the ExecutorService to terminate:

while (!executor.isTerminated()) {
}

The interface provides a method which blocks until the ExecutorService has terminated, which is typically much more CPU friendly: ExecutorService#awaitTermination(long,TimeUnit). The method accepts a timeout value to specify the maximum amount of time the thread should block awaiting termination. If you want to wait "forever" use a really large value, such as:

executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

Avoid Raw Types

I recommend reading What is a raw type and why shouldn't we use it?. The Callable interface is generic yet in some places you are using the raw type. Instead of having:

public class WorkerThread implements Callable {...}
// and
Callable worker = new WorkerThread(...);

You should have:

public class WorkerThread implements Callable<String> {...}
// and
Callable<String> worker = new WorkerThread<>(...);

UI Threading

Note you have a java.awt.Label which is being updated inside the processCommand method. Keep in mind that UI objects typically must only be accessed on the UI thread (e.g. the Event Dispatch Thread (EDT) in Swing). At least, that's the case with Swing—I'm not sure if AWT is thread-safe or not. That said, I'm not actually sure why you're using a Label since none of your code appears to be related to a GUI.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • Yes. I would have used `Callable`, but I would still need to return null in method `call`. – Maurice Perry Oct 15 '19 at 08:38
  • The OP has `List>` and `String result = executor.invokeAny(callList);`, so I was just trying to match that. – Slaw Oct 15 '19 at 08:47
  • @Slaw Thanks for this, I used the label so as to try to stop the thread by breaking the loop. In the if statement inside the loop, I set text to the label such that when the result is found, the label text will be updated and other thread will stop because they also check the text to see if it's stop. But it's not working though. – Hither Joe Oct 15 '19 at 13:32
  • @HitherJoe The contract of `invokeAny` states that after the first task completes (normally or exceptionally) all remaining tasks are cancelled. This means you should check if the current `Thread` is interrupted and, if so, break out of the loop. Also, if you aren't returning anything then use `Callable` and `return null;`. And get rid of the `Label` if you aren't programming a GUI; there are other classes for communicating across threads (e.g. `AtomicReference`), though again, in your case, you probably just need to check for thread interruption to see if a task has already completed. – Slaw Oct 15 '19 at 20:49