1

I'm new to threading in general, so bare me with here.

I was reading the following pages about Threading and Executors(1,2). Suppose I wanted to read a large text file asynchronously and return a List collection to iterate though.

According the second link:

The java.util.concurrent.ExecutorService interface represents an asynchronous execution mechanism which is capable of executing tasks in the background.

With this in mind I came up with the following code sample:

The text file (I'm aware the file is too small, let's assume that it had 100+ names):

Sally Solomon
Dick Solomon
Harry Solomon
Tommy Solomon

Code Sample:

String fileName = "C://Users//Nexusfactor//Desktop//read.txt";

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<List<String>> future = executorService.submit(new Callable<List<String>>(){
    public List<String> call() throws Exception {
        List<String> lstofNames = new ArrayList<String>();
        try (Stream<String> stream = Files.lines(Paths.get(fileName))) 
        {
            lstofNames = stream.collect(Collectors.toList());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lstofNames;
    }
});
executorService.shutdown();

List<String> display = future.get();

for(String view : display){
    System.out.println(view);
}

Is this the proper way to use a ExecutorService, Future and submit(Callable) to asynchronously read a text file into a list and then iterate though it?

  • 1
    Leaving aside that `future.get()` blocks on the particular thread, what issue are you having? – KevinO May 22 '17 at 18:50
  • 1
    No. That just makes your code slower, since instead of waiting for a file to be read from the main thread, it now has to create an executor, start a second thread that reads the same file, wait for the thread to complete the reading, and shutdown the executor. Your code is still synchronous, but uses two threads instead of one, where the first thread blocks and waits doing nothing while the second thread reads the file. – JB Nizet May 22 '17 at 18:52
  • @JBNizet - how would I correct it then? – Nexusfactor May 22 '17 at 18:58
  • @KevinO - I wanted to learn how to read a file asynchronously. – Nexusfactor May 22 '17 at 18:58
  • What's the reason you want to read a file asynchronously in the first place? And if you just want the main thread to continue doing something while another thread reads the file, why don't you simply make the other thread read **and print** the contents of the file? – JB Nizet May 22 '17 at 19:00
  • @JBNizet - No particualr reason why, I just wanted to learn how to do background tasks. – Nexusfactor May 22 '17 at 19:01
  • If you *truly* need such an approach, you will likely also wish to implement some sort of `Observer` pattern. Then you would use a `Producer/Consumer` pattern to submit the file to be read, and then receive the notification when it is done. Otherwise, as I asked, what issue are you having the code above? It seems like it should fire up a separate thread and read the file in that other thread. Which means you've learned the basics of a background task. BTW: put this into swing with a button to read the file; you'll have better luck seeing the approach. – KevinO May 22 '17 at 19:01
  • @KevinO - I don't have a problem with the code above. I just wanted to know if I used ExecutorService and Future correctly to read a text file asynchronously. I don't quite understand the commect JB Nizet is making – Nexusfactor May 22 '17 at 19:04
  • You succeeded, except there is no foreground task anymore, which makes it pointless. In a more realistic use-case, you would avoid creating an executor for each task, and reuse one instead, and send multiple tasks doing things concurrently, or avoid calling get() on the future to be able to do something on the main thread while the background thread is working. – JB Nizet May 22 '17 at 19:05
  • No, not at all. And a Runnable wouldn't allow to return anything anyway. You don't have any performance problem. You have an understanding problem. Let's say you're a standalone worker, and are overwhelmed. You decide to hire someone. That could reduce your workload if you tell the employee to do some of your tasks, and do something else while he's working on these tasks. But if instead you have to explain him what to do, and watch him, doing nothing, while he's working, that will only make things slower. That's what your code is doing. I'm not sure how I could explain it more clearly. – JB Nizet May 22 '17 at 19:23
  • @JBNizet - When/how can I call get to receive the list, and prevent it from blocking? – Nexusfactor May 22 '17 at 19:43
  • As I said, either don't call it at all, and let the background task print the list, or do something in the main thread while the background thread is waiting. But, again, there is no point at all in doing what you're doing. Your example is too contrived. If you want to do what your code does efficiently, just do it in a single thread. If you have a real, good use-case where a background thread is useful, then implement it and ask about it. This specific example is not a good use-case for an executor. – JB Nizet May 22 '17 at 19:53

1 Answers1

1

The issue is that the main thread immediately call future.get() and therefore blocks for the executor to take care of the file read. So in effect you are using 2 threads but only one at a time (for almost all the time).

Some examples on why would you want to use another thread / concurrency:

  1. Say there is another file (or a list of files) to be read then you can spin up an executor (not a single threaded) to read multiple files in parallel.
  2. Say this is a huge file and you would like to break apart the reading of the file into multiple tasks that are run concurrently.
  3. Say there is a DB call that can be done concurrently to the reading of the file. You could put this in another task for the executor to take care of or let the main thread take care of it.
  4. And so on.

Remember what I write above are examples that assist in thinking. What you would need to do is to look at your requirements and then design and write the code for concurrency. In this specific case, there is no need for concurrency (due to the immediate future.get() invocation).

EDIT 1 (based on your comments): If your aim is to understand writing asynchronous tasks then your goal is met with the contrived example that you have listed. However, you can make it more realistic by thinking on the examples that I have provided you or you can think some of your own.

Khanna111
  • 3,627
  • 1
  • 23
  • 25