0

I'm learning executor service in java. Requirement is using executor service create 4 threads -

Thread 1 - get two numbers as input.

Thread 2 - addition of two numbers

Thread 3 - multiplication of two numbers

Thread 4 - print the results.

Thread 1 should be executed first, after thread 1 is complete thread 2, 3 can start processing simultaneously and finally once thread 2, 3 is completed. Thread 4 should run finally.

How can we make sure which thread starts first and which threads to start simultaneously next. Finally which thread to execute at last.

Note: How can we achieve this without using thread sleep. Dynamically as soon as thread 1 finishes other two threads should start automatically.

4
  • Thread 1 could start Thread 2 and 3(and maybe Thread 4). Thread 4 could join all Threads. Commented Feb 2, 2020 at 17:14
  • What have you tried and what doesn't work with it? Commented Feb 2, 2020 at 17:21
  • 1
    FYI, This exercise might teach you something about how to use threads, but it is the absolutely worst example of why to use threads. It's like, somebody is teaching you how to operate a car by having you use the car's front bumper to ram the nails home in a piece of furniture that you are building. I'm serious. This example is that bad. If a program needs to do certain things in a certain order, the only right way to do that is to do all of those things in a single thread. The entire point of threads is to enable you to do things concurrently (which means, in no particular order.) Commented Feb 2, 2020 at 18:00
  • 1
    Also note: Don't think of executor service as a way to create threads. Think of it as a way to perform background tasks. The whole point of an executor service is to shield you, as much as possible, from having to think about the "worker threads" that it uses to perform your tasks. Commented Feb 2, 2020 at 21:34

2 Answers 2

2

First, Read my comment on your original question--the one about using a car to hammer in nails.

Ok, Now, @dan1st had some ideas about how to structure the solution. Here's two more.

  1. Use a global int variable, a global lock, and wait() and notifyAll(): Have each thread enter a synchronized(lock) block in which it

    • Loops, calling lock.wait() until the global int has some particular value,
    • Does its trick,
    • Sets the global int to the value that will trigger the next thread,
    • calls lock.notify(), and finally
    • exits
  2. Use Semaphores: Pass two Semaphore instances in to each thread. Call them in and out or some such names. Have each thread

    • wait its turn by calling in.acquire(),
    • do its trick,
    • call out.release(),
    • and then exit.

Your main routine then is responsible for creating the semaphores, and passing them to the new threads in such a way that each thread's out refers to the same semaphore as the in of the thread that is expected to perform the subsequent task.


IMO, option 2 is more elegant, because if your teacher asks you next week to modify your program by adding another step in the middle of the sequence, then none of the existing tasks that you wrote will have to change at all. You'll only need to write the new task and change two or three lines in the main() routine.

Doesn't sound like much of an improvement, and option 2 clearly is more work to set up in the first place than option 1, but if you ever are employed to work on enterprise-scale software systems with millions of lines of code, you will come to appreciate the beauty of option 2.

Sign up to request clarification or add additional context in comments.

1 Comment

P.S., If I ever teach a programming class, my students will learn real quick to expect, "now, change the program you wrote last week so that..." Out in the real world, requirements change. Often. One of the most important skills a developer can learn is how to write code that you don't have to throw away and start from scratch every time the requirements change.
1

You could do this using multiple ways.

For exanple, joining:

A Thread can join another Thread, which means that it waits until the other Thread finishes. Thread 2 and 3 could join Thread 1 and Thread 4 could join Thread 2 and 3.

Another possibility is await and signal but I am not sure if it meets your Requirements(it uses something similar to Thread.sleep():

At first, you create a common java.util.concurrent.locks.Lock and create a condition of this lock with .newCondition() You also create a second condition using newCondition().

The lock has to be locked before calling await and signal/signalAll.

Thread 2 and 3 calls .await() on the first condition before starting and Thread 1 calls .signalAll on the first condition when it finishes.

Thread 4 calls .await() on the second condition before it starts.

The Thread (either 2 or 3) that finishes last(the logic which Thread finished first should be synchronized with the lock) calls .signal() on the second condition.

The threads could also start each other:

Thread 1 starts Thread 2 and 3 after it's task finishes but I would recommand you one of the other mechanisms for Thread 4.

[DISCLAIMER]

You may not be able to interact with the Threads directly if you use an ExecutorService. This post might help you with joining, await/signal should not be more difficult and the Threads can also schedule a task to the thread pool if needed.

1 Comment

Thanks a lot. I understood your idea in basic java thread concept. Is this concept actually same in java 8 also..?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.