Call to method with a thread inside implies a wait? - java

I have a method that writes a file and it can be a bit slow. So I did this to avoid blocking the rest of actions:
// things A
method();
// things B
public void method(){
new Thread(() -> {
// slow stuff
}).start();
}
However it still takes a while until things B are executed after things A and I was wondering if I should do this instead:
// things A
new Thread(() -> {
method();
}).start();
// things B
public void method(){
// slow stuff
}
Or, in other words, does calling a method with a thread inside it imply waiting for the method to end, and therefore the thread?
Just to clarify things: I want to know if both options would be the same or if in the first option the thread should finish for the B instructions to start.

Does calling a method with a thread on it imply waiting for the method to end, and therefore the thread?
No. To highlight that the thread isn't a factor, I took your original code:
method();
// things B
public void method(){
new Thread(() -> {
// slow stuff
}).start();
}
And sprinkled a bunch of System.out.println() calls throughout:
one before calling method(), and one right after
one at the start of method(), and one at the end
one at the start of the thread body, and one at the end
Also:
the thread does "slow stuff" by calling Thread.sleep() for 2 seconds
each println() includes current date+time
the output is crudely formatted with indentation to show the start/end pairs of each output
import java.time.LocalDateTime;
public class ThreadExample {
public static void main(String[] args) {
System.out.println("main >> " + LocalDateTime.now());
new ThreadExample().method();
System.out.println("main << " + LocalDateTime.now());
}
public void method() {
System.out.println(" method >> " + LocalDateTime.now());
new Thread(() -> {
System.out.println(" thread >> " + LocalDateTime.now());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(" thread << " + LocalDateTime.now());
}).start();
System.out.println(" method << " + LocalDateTime.now());
}
}
Output below, which shows a few things:
the first+second output lines in main (before and after calling method()) are basically instantaneous – 09:10:22.036305 start, 09:10:22.037957 end, for a difference of 0.001652 seconds
same for method(), nearly instantaneous with start of 09:10:22.037564 and end of 09:10:22.037897, which is a difference of 0.000333 seconds
the start and finish outputs in thread are where the waiting is, starting at 09:10:22.037920, ending at 09:10:24.041840; total difference of 2.00392 seconds which is the 2 seconds we asked for with Thread.sleep() plus the tiny amount of execution time similar to the others (0.00392)
perhaps most importantly for this question, it's clear that both the original caller (in main()) and method() both finish before thread finishes ~2 seconds later
main >> 2022-06-17T09:10:22.036305
method >> 2022-06-17T09:10:22.037564
method << 2022-06-17T09:10:22.037897
thread >> 2022-06-17T09:10:22.037920
main << 2022-06-17T09:10:22.037957
thread << 2022-06-17T09:10:24.041840

Related

How to execute async methods in Order?

I have a custom asynchronous method and I know threads are executed randomly, but I want to execute them in order.
I want to solve the problem in the main() method.
I've tried Thread.sleep() but it's not useful.
public static void main(String[] args) throws Exception{
Monster monster = new Monster();
System.out.println(1);
monster.exe();
System.out.println(2);
monster.exe();
System.out.println(3);
monster.exe();
System.out.println(4);
}
Class Monster
class Monster {
public void exe() {
new Thread(() -> {
System.out.println("Monster...: "+ Thread.currentThread().getName());
}).start();
}
}
That's doable, but frankly pointless because such a "parallel" execution even less performant than sequential processing of these tasks.
If you are doing that just as an exercise, that's OK. Otherwise, either don't try to control the execution of these tasks or do it in a single-threaded environment.
For that, you might use method join():
public static void main(String[] args) throws InterruptedException {
Monster monster = new Monster();
System.out.println(1);
Thread thread1 = monster.exe();
thread1.join();
System.out.println(2);
Thread thread2 = monster.exe();
thread2.join();
System.out.println(3);
Thread thread3 = monster.exe();
thread3.join();
System.out.println(4);
}
Each call of join() will block the main thread until another thread (on which this method was invoked) isn't finished its job.
Note: method join() throws InterruptedException which is a checked exception and must be either handled with a try/catch or should be signified in the method declaration. I've deliberately chosen the second option in order to make the code simpler and keep focus on what it is intended to do. But you should know that it's not a good practice to add the throws clause to the declaration of the main() method.
A small change was done to the Monster class (method exe() returns a thread that has been created in order to be able to join on it).
public class Monster {
public Thread exe() {
Thread thread = new Thread(() -> {
System.out.println("Monster...: "+ Thread.currentThread().getName());
});
thread.start();
return thread;
}
}
Output
1
Monster...: Thread-0
2
Monster...: Thread-1
3
Monster...: Thread-2
4
Another way to do it is to extract the codes that you want to execute asynchronously into a separate Runnable :
Runnable newMonstorTask() {
return ()->System.out.println("Monster...: " + Thread.currentThread().getName());
}
And then use CompletableFuture to configure them to execute in order and asynchronously :
CompletableFuture.runAsync(newMonstorTask())
.thenRunAsync(newMonstorTask())
.thenRunAsync(newMonstorTask())
.thenRunAsync(newMonstorTask());
You can use CompletableFuture and then methods like thenApply().
Please look here: https://www.deadcoderising.com/java8-writing-asynchronous-code-with-completablefuture/

Thread execution output

For the given code snippet:
public static void main(String[] args) throws InterruptedException {
Runnable r = new Runnable() {
public void run() {
System.out.print(Thread.currentThread().getName());
}
};
Thread t1 = new Thread(r, "One ");
t1.start();
t1.sleep(2000);
Thread t2 = new Thread(r, "Two ");
t2.start();
t2.sleep(1000);
System.out.print("Main ");
}
The output is always coming as "One" "Two" "Main". Why is such behavior with threads in this code? Why always "t1" is starting first and not "t2" or main thread for that matter?
Thread.sleep() is a static method which pauses the current thread. The "current" thread here means the "thread from which the sleep() call was invoked": in this code that is always the main thread.
So your code is equivalent to, and should be written as
public static void main(String[] args) throws InterruptedException {
Runnable r = new Runnable() {
public void run() {
System.out.print(Thread.currentThread().getName());
}
};
Thread t1 = new Thread(r, "One ");
t1.start();
Thread.sleep(2000);
Thread t2 = new Thread(r, "Two ");
t2.start();
Thread.sleep(1000);
System.out.print("Main ");
}
What happens is that you start t1, pause the main thread for two seconds, then start t2, pause the main thread for another second, and then print "Main " to the console.
Technically, there is no guarantee as to how long it will be between calling t1.start() and System.out.println("One ") (from t1's runnable), and there is no guarantee as to how long it will be between calling t2.start() and System.out.println("Two "). For all practical purposes, though, these will be at most of the order of milliseconds.
However, you are guaranteed that there will be at least two seconds between calling t1.start() and t2.start(), and that there will be at least one second between calling t2.start() and System.out.println("Main ").
So for all practical purposes, you will print "One " to the console, then two seconds (plus or minus a few milliseconds, at most) later print "Two " to the console, then another second (plus or minus a few milliseconds) later print "Main ".
Any good (and reasonably configured) IDE will warn you when you refer to a static method via an object reference, as you do with t1.sleep(2000), etc. You should not ignore these warnings and should correct the code, so that it is clearer what you are doing.
here we have total three threads main, t1, t2. when execution starts all the threads in pool are executing in asynchronously, because threads of the same priority are given equal treatment by the java scheduler and, therefore they run on a first-come, first-serve basis.
use threadname.setPriority(intNum) method to assign priority, which affects the order of running threads.

notifyAll() not awakening processes

I'm programming a little Java program where I need to create threads (philosophers in my code), and these philosophers need to change of state between thinking, hungry and eating.
I'm not that far into the project and I have the next problem:
public class NewMain {
static Philosopher [] p;
public static void main(String[] args) {
p = new Philosopher[5];
p[0] = new Philosopher(0);
p[1] = new Philosopher(1);
p[2] = new Philosopher(2);
p[3] = new Philosopher(3);
p[4] = new Philosopher(4);
for (int i = 0; i<5; i++) {
try{
p[i].run();
if(i == 4) {
p.notifyAll();
}
}
catch(IllegalMonitorStateException e) {}
}
}
}
I'm creating 5 philosophers(threads). Each one of those has a wait() instruction in their code:
#Override
public void run() {
int rand;
if (status == 0) {
System.out.println("Philosopher " + id + " is waiting.");
try {
wait();
System.out.println("Awoken");
while(status == 0) {
System.out.println("Philosopher " + id + " is thinking.");
sleep(100);
rand = ThreadLocalRandom.current().nextInt(0,100);
if(rand > 95){
status = 1;
System.out.println("Philosopher " + id + " changed state to hungry.");
}
}
}
catch(InterruptedException e) {
System.out.println("Error!");
}
catch(IllegalMonitorStateException e) {}
}
}
The problem is that when invoking notifyAll(), the processes don't awake and they just die after executing the run() method of each thread.
If anyone is wondering, I'm not using synchronized because I need to run the methods at the same time.
Also, I've tried to put notifyAll() inside the run() method of the threads.
Can anyone tell me what's going on and why are the threads not continuing
with their code?
Problems
notify[All]() and wait() should be used on the same instance. You are notifying on the array Philosopher[] p, but waiting on this which is a Philosopher. It's like I am waiting for you, but you are notifying Sarah that you're going to be late.
You have created the threads but haven't started them properly. Calling run will execute the method in the current thread. Use the method start instead. It begins execution concurrently.
To use x.notify[All]() or x.wait(), you have to be within a synchronised block synchronized(x) { ... }. Ignoring IllegalMonitorStateException won't help you at all.
Answers
... why are the threads not continuing with their code?
They might call wait after the 4th thread notifies them.
... the processes don't awake and they just die ...
They don't die, they still wait until you terminate the program.
I'm not using synchronizedbecause I need to run the methods at the same time
You need to run the methods at the same time correctly, right? Here, synchronisation is required at least for building wait-notify communication.
p is an array of Runnable. when you write
p[i].run();
Then, you are invoking run method (actually you haven't started a thread here instead called run method) using object stored at p[i] location. Now, as per notifyAll
Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.
You should have used start() instead run() to start a new thread.
notify() and notifyAll are used when thread(s) are waiting to acquire monitor on current object.

Java thread join 3

The program creates thread t0 which spawns thread t1 and subsequently threads t2 and t3 are created.After the execution of thread t3and the application never returns to the other threads spawned earlier(t0,t1,t2) and they are left stuck.
Why are the threads t0, t1, and t2 suspended?
public class Cult extends Thread
{
private String[] names = {"t1", "t2", "t3"};
static int count = 0;
public void run()
{
for(int i = 0; i < 100; i++)
{
if(i == 5 && count < 3)
{
Thread t = new Cult(names[count++]);
t.start();
try{
Thread.currentThread().join();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
System.out.print(Thread.currentThread().getName() + " ");
}
}
public static void main(String[] a`)
{
new Cult("t0").start();
}
}
The most important point you missed:
Thread.currentThread().join();
Method join in source code uses isAlive method.
public final synchronized void join(long millis)
...
if (millis == 0) {
while (isAlive()) {
wait(0);
}
...
}
It means that Thread.currentThread().join() will return only when Thread.currentThread() is dead.
But in your case it's impossible because of your running code in Thread.currentThread() has itself
this peace of code Thread.currentThread().join(). That's why after Thread 3 completion your program should hang and nothing happens thereafter.
Why are the threads t0, t1, and t2 suspended? The execution of thread t3 completes.
t3 completes because it is not trying to fork a 4th thread and therefore is not trying to join() with it's own thread. The following line will never return so t0, t1, and t2 all stop there and wait forever:
Thread.currentThread().join();
This is asking the current thread to wait for itself to finish which doesn't work. I suspect that you meant to say t.join(); which is waiting for the thread that was just forked to finish.
Here are some other thoughts about your code in no apparent order:
You should consider implements Runnable instead of extends Thread. See here: "implements Runnable" vs. "extends Thread"
You are using the shared static variable count in multiple threads without any protection of locking. The best solution is to use an AtomicInteger instead of a int. You probably don't have a problem here because each thread is modifying count and then forking another thread but if you tried to fork 2 threads, this would be a real problem because of data race conditions.
I'm not sure why you are only spawning another thread if(i == 5 && count < 3). i is only going to be 5 once in that loop. Is that really what you intended?
String[] names = {"t1", "t2", "t3"}; fields are recommended to be declared at the top of classes. Otherwise they get buried in the code and get lost.
In main you start a Cult thread and then the main thread finishes. This is unnecessary and you can just call cult.run(); in main instead and use the main thread.
Cult(String s) { super(s); } there is no point in having a constructor that calls the super constructor with the same arguments. This can be removed.
This is debatable but I tend to put main method at the top of the class and not bury it since it is the "entrance" method. Same thing with constructors. Those should be above the run() method.
catch(Exception e) {} is a really bad pattern. At the very least you should do a e.printStackTrace(); or log it somehow. Catching and just dropping exceptions hides a lot of problems. Also, catching Exception should be changed to catch(InterruptedException e). You want to restrict your catch blocks just the exceptions thrown by the block otherwise this may again hide problems in the future if you copy and paste that block somewhere.
More a good practice but never use constants like 3 that have to match another data item. In this case it would be better to use names.length which is 3. THis means that you don't need to change 2 places in the code if you want to increase the number of threads. You could also have the name be "t" + count and get rid of the names array altogether.

Understand the concept of MultiThreading in Java

Recently I have gone through with one simple threading program, which leads me some issues for the related concepts... My sample program code looks like :
class NewThread implements Runnable {
Thread t;
NewThread() {
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t);
t.start(); // Start the thread
}
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
Now this program giving me the output as follows :
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.
So, that's very much clear to me. But as soon as I am replacing the object creation code (calling of a NewThread class constructor) to as follows :
NewThread nt = new NewThread(); // create a new thread
the output becomes a bit varied like as follows :
Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Child Thread: 3
Main Thread: 4
Child Thread: 2
Child Thread: 1
Main Thread: 3
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.
And some times it's giving me same output in both the cases. So, i am not getting the exact change in both the scenario.
I would like to know that you the variation in the output is coming here ?
Thanks in advance...
The changed output is due to nature of both OS process scheduling and JVM thread scheduling. Even if you take out the second thread there is no guarantee that your thread will wake-up exactly after 500ms.
I'm not sure I understand the change that you mention, but the scheduling is non-deterministic, i.e., it may schedule the threads differently in different runs of the application.
Another thing; creating and starting a new thread in the constructor isn't really best practice. Have you considered letting NewThread extend Thread? Like this:
class NewThread extends Thread {
NewThread(String str) {
super(str);
System.out.println("Child thread: " + this);
}
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
public class ThreadDemo {
public static void main(String args[]) {
new NewThread("Demo Thread").start();
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
You have two threads, one which does something about every half second, one which does something about every second.
The JVM and OS makes no guarantee which of the threads available for scheduling gets run at a given time. Alternatively, if you have multiple cores then both threads could be running at the same time, and competing for a lock on the System.out that stops two threads printing at the same time - if you send the output one character at a time instead of using println, then the characters from both thread's output might be mixed together.
Your output shows that at one second and at two seconds, which of the two threads prints its output it is not predictable. This is as expected.
It makes no difference in this case whether or not you assign the NewThread object to a local variable. The object is not eligible for garbage collection while the thread it is running in is running (assuming Threads hold a reference to their runnable), and nothing else uses the local variable. So the difference after that change in the code is just the randomness in the scheduling, not the effect of the change.
As mentioned above, this is normal behaviour. If you need some tasks started at a specific time and/or at a fixed interval, then the Timer's scheduleAtFixedRate() may give you a better result.
Are both outputs correct for both programs? Yes.
The answer is the output is undefined. The particular (correct) output you get each time could depend on just about anything, including minor variations in the compiled bytecode. (It might be worth checking this with javap -c, just to be sure the difference in code is a possible cause.)
In general if you have two threads doing things in parallel, you can't be sure of the ordering of their combined output unless you synchronise them somehow.

Categories

Resources