0

i want to run 2 or more threads sequentially , by this I mean for example : first it should run the first thread then the second one and ... . i had used Executors.newSingleThreadExecutor(); too. I have 3 tasks :1-create a file 2- write something in that 3- read the file the create task:

 public class FirstTask implements Runnable{
 private CreateRoleFile createFiel = new CreateRoleFile();
  @Override
  public void run() {
    createFiel.createFile();
}

}

the createFile() method:

    public Path createFile(){

    Path path = Paths.get("Files/first.txt");

    if (!Files.exists(path)) {
        try {
            Files.createFile(path);

        } catch (IOException e) {
            System.out.println("something went wrong while creating first.txt .Please try again!");
        }
        System.out.println("thread name = "+Thread.currentThread().getName());
        return path;
    } else {
        System.out.println("This file is already exist!!");
        System.out.println("thread name = "+Thread.currentThread().getName());
        return path;
    }
}

the SecondTask class is :

public class SecondTask implements Runnable {
WriteRoleFile writeFile = new WriteRoleFile();

@Override
public void run() {
    writeFile.Writefile("1020");
}

} and this is my main method :

 public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService1 = Executors.newSingleThreadExecutor();
    Runnable firstTask =new FirstTask();
    executorService1.execute(firstTask);
    executorService1.shutdown();

   ExecutorService executorService2=Executors.newSingleThreadExecutor();
   Runnable secondTask = new SecondTask();
   executorService2.submit(secondTask);
    executorService2.shutdown();

   ExecutorService executorService3 =Executors.newSingleThreadExecutor();
    Callable thirdTask=new ThirdTask();
    executorService3.submit(thirdTask);
    executorService3.shutdown();
}

the ThirdTask class is :

public class ThirdTask implements Callable<String> {
ReadRoleFile readeer = new ReadRoleFile();

@Override
public String call() {
    String s = readeer.readFile();
    return s;
}

}

the readFile() method is :

public String readFile() {
    Path path = Paths.get("Files/first.txt");
    String s = "";
    try {
        if (Files.size(path) == 0) {
            System.out.println("nothing has been wrote yet .");
        } else {
            try {
                BufferedReader bufferedReader = Files.newBufferedReader(path);
                s = bufferedReader.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("thread name = " + Thread.currentThread().getName());
    System.out.println(s);
   return s;
}

and the out put is : This file is already exist!! thread name = pool-1-thread-1 thread name = pool-3-thread-1 null thread name = pool-2-thread-1

**I need to first the pool-1-thread-1 run and the pool-2-thread-1 because it has to write a number in a file first and then pool-3-thread1 to read from file **

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
leylihz
  • 15
  • 1
  • 5
  • 1
    Glad to see you participating in Stack Overflow. Please write your prose with proper case, punctuation, and such. This site is meant to be more like Wikipedia, and less like a casual chat room. – Basil Bourque Apr 13 '21 at 06:47

3 Answers3

1

Keep a single executor service, for successive use

An executor service is backed by a pool of one or more threads. The purpose of the executor service is to:

  • Manage the creation, expiration, and scheduling of those threads
  • Assign your tasks (your Runnable or Callable objects) to those thread(s) for execution.

So keep your ExecutorService object around. You are creating new ones and then shutting them down. If you want to run three tasks in a row, use only a single executor service.

ExecutorService es = Executors.newSingleThreadExecutor();

Runnable task1 = new FirstTask();
es.execute( task1 );

Runnable task2 = new SecondTask();
es.execute( task2 );

Runnable task3 = new ThirdTask();
es.execute( task3 );

es.shutdown();              // Disallow any more tasks to be submitted.
es.awaitTermination( … ) ;  // Wait for submitted tasks to be done/canceled/failed.

The reason you got seemingly crazy behavior with your multiple executor service objects is that which executor service gets how much execution time when on the CPU core is not predictable. Your second executor service might have started first, but been suspended midway through its work. Meanwhile the third executor service may start and finish its work, even before the first executor service starts its work.

Each time you run your app, the order of which went first-second-third, and which finished in what order, will all vary. Scheduling of tasks on the CPU core is done at the whim of the JVM and host OS, varying by momentary conditions at runtime.

If you want a series of tasks to be done in order on a single background thread, use a single newSingleThreadExecutor() object to assign all those tasks.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • thanks a lot for your complete explanation .I totally understand my awful mistake ;)) – leylihz Apr 15 '21 at 14:28
  • @Basil Bourque To obtain a result from the Future, one can use the ExecutorService to deliver the result via the .get(); method. But that method will block until it gets the data. So do you ever recommend using a CompletableFuture and .supplyAsync() and thenApply() to obtain the result without blocking? If so, do I need to still set up a Callable in that case for the CompletableFuture or just set up a CompletableFuture? – AJW Apr 16 '21 at 00:59
  • @AJW If waiting on a bunch of tasks to all finish, collect their `Future` object returned when you submit to executor service. Then after service shutdown completes, loop the collection of futures to see if done or canceled or failed. If you want return value, then yes use `Callable` rather than `Runnable`. If you want a chain of tasks then yes `CompletableFuture`. But FYI, in the future, Project Loom technology may eliminate the need for most of the many methods and usages of CompletableFuture. See talks by Ron Pressler and other Oracle staff working on Loom. – Basil Bourque Apr 16 '21 at 01:06
  • @Basil Bourque Thanks. But my tasks are quite simple like inserting a small amount of data from a CardView into Room database, or updating that data, or deleting that data or requesting all of the data from Room for a List to show in a RecyclerView of CardViews. Over time the List of CardViews could grow and I definitely don't want to use .get() if the UI gets blocked. That is why I was looking to CompletableFuture as a potential solution since it does not block. I am trying to replace existing AsyncTask() since that method is deprecated. Would appreciate your thoughts or ideas. – AJW Apr 16 '21 at 01:20
  • @AJW All that has been covered many times already on Stack Overflow. Search to find much info. – Basil Bourque Apr 16 '21 at 01:34
0

This may not be an exact answer to your question.
We can control the execution of threads with the flags as shown below.
Order of execution Thread1 --> Thread2 --> Thread3 always.

import com.google.common.collect.Lists;

import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

AtomicBoolean flag1 = new AtomicBoolean(false); // to indicate Thread1 completed execution
AtomicBoolean flag2 = new AtomicBoolean(false); // to indicate Thread2 completed execution
final CopyOnWriteArrayList<String> result = new CopyOnWriteArrayList<>(); // thread safe collection just to capture results from threads

Callable<Void> r1 = () -> {
    result.add("Thread1 : " + Thread.currentThread().getName());
    flag1.set(true);
    return null;
};

Callable<Void> r2 = () -> {
    while (!flag1.get()) {
        System.out.println("thread2 waiting");
    }
    result.add("Thread2 : " + Thread.currentThread().getName());
    flag2.set(true);
    return null;
};

Callable<Void> r3 = () -> {
    while (!flag2.get()) {
        System.out.println("thread3 waiting");
    }
    result.add("Thread3 : " + Thread.currentThread().getName());
    return null;
};

// using same executor service for all the threads as suggested from this answer: https://stackoverflow.com/a/67069903/2987755
ExecutorService ec = Executors.newCachedThreadPool();

// call all the threads
ec.invokeAll(Lists.newArrayList(r1, r2, r3));

// we do not need ExecutorService anymore so shutting it down
ec.shutdown();

// print results
System.out.println(result);


//output
// truncated system out waiting log
//[Thread1 : pool-1-thread-1, Thread2 : pool-1-thread-2, Thread3 : pool-1-thread-3]

dkb
  • 4,389
  • 4
  • 36
  • 54
  • `flag1.get()` is non blocking, your while loop will execute non stop. You could use wait()/notify() or better option [java.util.concurrent.locks.Lock](https://stackoverflow.com/a/4916691/15273968) class. – the Hutt Apr 13 '21 at 07:11
0

As you are doing the three tasks sequentially then you need only one ExecutorService with only one thread. Submit all the tasks and wait for the results:

String fileName = "e:\\temp.txt";
Callable<Path> createTask = ()->{System.out.println("File created"); return Path.of(fileName);}; 
Runnable writeTask = ()->{System.out.println("Written to the file"); /*put write code here*/};
Callable<String> readTask = ()->{System.out.println("Reading from the file"); return "fileData 1020";};

ExecutorService es = Executors.newSingleThreadExecutor();
es.submit(createTask);
es.execute(writeTask);
Future<String> f = es.submit(readTask);

es.shutdown();
String data = f.get(); //wait for readTask to finish then get data
System.out.println("Read Data is: " + data);

Output:

File created
Written to the file
Reading from the file
Read Data is: fileData 1020

Here I am using lambdas to define tasks to keep it simple.
ExecutorService maintains a queue of all summitted tasks. As we have only one thread in this service all the tasks will be executed one by one in first in first out fashion.
Also we are taking Future<String> object to retrieve the file read results. Future#get() waits for task to complete and then returns the result.

the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • I have a similar use case, trying to convert AsyncTasks to ExecutorService to return a List from a Room database. Another answer suggests using submit() on ExecutorService and get() on the Dao method (see stackoverflow.com/questions/52242933/room-database-query). Would appreciate your thoughts on that approach versus the approach above using a Callable and a Future. – AJW Apr 13 '21 at 20:41
  • 1
    Actually, he's not calling get() on the Dao. He is also doing the same thing as I did here. It's just that he has directly called get() on the future object returned by submit() method. He is not storing the future object in any variable. Also, if you don't want to block on get() method then try this https://stackoverflow.com/q/35366018/15273968. Or use `CompletableFuture.supplyAsync(()->{return Test.task();}) .thenApply((s)-> {System.out.println("Task output: " +s);return "";});` – the Hutt Apr 14 '21 at 02:24
  • So in his case, the future object is the String "name"? Thanks for non-blocking recommendation, I will review. – AJW Apr 14 '21 at 17:12
  • Follow-up: do I still need to set up a Callable first when using CompletableFuture? – AJW Apr 16 '21 at 00:30