I'm writing a program where the Main class initializes and starts a master thread. This master thread starts n slave threads. The program should terminate using Ctrl+C. Master thread must stop slave threads and finally stop itself.
I've read a lot about addShutdownHook and here is my simplified implementation:
package dictator;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Master m = new Master();
m.start();
}
}
class Master extends Thread {
List<Slave> slaveMonitor = new ArrayList<Slave>();
public Master() {
for (int i = 0; i < 4; i++) {
Slave slaveThread = new Slave();
slaveMonitor.add(slaveThread);
}
Thread shutDown = new Thread() {
#Override
public void run() {
try {
System.out.format("%nShutting down threads...%n");
for (Slave s : slaveMonitor) {
s.interrupt();
s.join();
}
interrupt()
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
};
Runtime.getRuntime().addShutdownHook(shutDown);
}
#Override
public void run() {
for (Slave s : slaveMonitor) {
s.start();
}
while (true) {
System.out.println(getName() + " - Master");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(getName() + " interrupted.");
break;
}
}
System.out.println(getName() + " exiting.");
}
}
class Slave extends Thread {
public Slave() {}
#Override
public void run() {
while (true) {
System.out.println(getName() + " - Slave");
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {
System.out.println(getName() + " interrupted.");
break;
}
}
}
}
The addShutdownHook catches the signal and terminates all slaves threads, but I'm not seen the master thread exiting (lines System.out.println(getName() + " interrupted."); and System.out.println(getName() + " exiting."); in master's run body.
Here is my terminal's output:
Thread-1 - Slave
Thread-2 - Slave
Thread-3 - Slave
Thread-0 - Master
Thread-4 - Slave
Thread-0 - Master
^C
Shutting down threads...
Thread-1 interrupted.
Thread-2 interrupted.
Thread-3 interrupted.
Thread-4 interrupted.
Shouldn’t I see the line following lines? What I'm I doing wrong?
Thread-0 interrupted.
Thread-0 exiting.
Changed Master Thread
class Master extends Thread {
List<Slave> slaveMonitor = new ArrayList<>();
List<Thread> killList = new ArrayList<>();
public Master() {
for (int i = 0; i < 4; i++) {
Slave slaveThread = new Slave();
slaveMonitor.add(slaveThread);
}
killList.add(this);
Thread shutDown = new Thread() {
#Override
public void run() {
try {
killList.addAll(slaveMonitor);
Collections.reverse(killList);
System.out.format("%nShutting down threads...%n");
for (Thread t : killList) {
t.interrupt();
t.join();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
System.out.println("Interrupted shutdown process");
System.exit(1);
}
}
};
Runtime.getRuntime().addShutdownHook(shutDown);
}
...
Your shutdown thread never interrupt the master thread. It is a separate thread from the Master thread so when you call
interrupt()
in its body you are asking this thread to interrupt itself. You need to add the master thread to the list of thread to terminate.
Change your code to :
List<Thread> killList = new ArrayList<Thread>();
....
for (int i = 0; i < 4; i++) {
Slave slaveThread = new Slave();
slaveMonitor.add(slaveThread);
}
killList.addAll(slaveMonitor);
killList.add(this);
and use the killList to terminate threads.
1)Create a program which makes use of two types of threads: slaves (sensors) and master.
The slave threads collect measurements and forward them to the master thread
For sake of simplicity the slaves measure the current time (System.currentTimeMillis()). Only the master thread outputs the values to the console. The measures are stored in a shared variable. The number of slaves shall be read from the console.
Related
I have been learning multithreading in Java since recently and I encountered an example in the book. It goes something like this.
class NewThread implements Runnable {
String name;
Thread t;
boolean suspendFlag;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
suspendFlag = false;
t.start();
}
public void run() {
try {
for(int i = 15; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
synchronized void mysuspend() {
suspendFlag = true;
}
synchronized void myresume() {
suspendFlag = false;
notify();
}
}
class Te {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending thread One");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming thread One");
ob2.mysuspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.myresume();
System.out.println("Resuming thread Two");
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Now in this example as you can see, there is a resume and a suspend method which gets called a couple of times in the program's main method. But when I remove the synchronized block in the run method, it displays an error something like this.
Exception in thread "Two" java.lang.IllegalMonitorStateException
I acually wanted to know, why do we need the synchronized block for the while statement. Doesn't the while resume when the value of suspendFlag change?
Here's what could happen if there was no synchronization:
Thread A could check suspendFlag and find it to be true,
Thread B could set suspendFlag=false; and then call notify();
Thread A could then call wait() (because suspendFlag was true when it checked.), and now Thread A is hung, waiting for a notification that will never happen.
The synchronization prevents thread B from changing the suspendFlag in between the moment when thread A checked it, and the moment when thread A actually begins to wait for the notification.
I'm learning Thread in java.
The following example shows how to suspend, resume and stop threads:
class MyNewThread implements Runnable {
Thread thrd;
boolean suspended;
boolean stopped;
MyNewThread(String name) {
thrd = new Thread(this, name);
suspended = false;
stopped = false;
thrd.start();
}
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
for(int i = 0; i<1000; i++) {
System.out.print(i + " ");
if(i%10 == 0) {
System.out.println();
Thread.sleep(250);
}
synchronized(this) {
while(suspended) {
wait();
}
if(stopped) break;
}
}
} catch(InterruptedException ex) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " exiting.");
}
synchronized void mystop() {
stopped = true;
suspended = false;
notify();
}
synchronized void mysuspend() {
suspended = true;
}
synchronized void myresume() {
suspended = false;
notify();
}
}
public class Suspend {
public static void main(String[] args) {
MyNewThread ob1 = new MyNewThread("My Thread");
try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending Thread.");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming Thread.");
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending Thread.");
Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming Thread.");
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Stopping Thread.");
ob1.mystop();
} catch(InterruptedException ex) {
System.out.println("Main Thread interrupted.");
}
try {
ob1.thrd.join();
} catch(InterruptedException ex) {
System.out.println("Main Thread interrupted.");
}
System.out.println("Main Thread exiting.");
}
}
But this block:
synchronized(this) {
while(suspended) {
wait();
}
if(stopped) break;
}
Why this block must be specified synchronized?
I know "synchronized" uses to control Threads's access to shared resource and how to use this key word, but in the example, there're only 2 threads: Main thread and ob1 thread. And Main thread does not enter that synchronized block or any synchronized method in MyThread class. I just cant figure out the reason.
I tried to remove the "synchronized" key word precedes the block. the program returned an error in thread "My Thread" while the main thread still finished it's execution.
To answer your direct question: you need to synchronize on this because you are calling wait() on this.
And in order for wait() to be called, the calling thread must own the monitor of the object wait() is called on.
So: you need that synchronized block (or method) to prevent an IllegalMonitorStateException for the following call to wait()!
I am using single thread executor for long-running threads like this:
executor = Executors.newSingleThreadExecutor(THREAD_FACTORY);
executor.submit(new LongRunnable());
which checks a flag to be stopped:
private class LongRunnable implements Runnable {
#Override
public void run() {
while (isRunning.get()) {
try {
doSomething();
} catch (InterruptedException e) {
...
}
}
}
}
and whole execution is interrupted that way:
#Override
public void close() throws Exception {
isRunning.set(false);
executor.shutdownNow();
}
Still I can see some threads not gc-ed in profiler (while by logs, runnable they were executing has quit outermost while loop).
Question: does provided working with threads strategy memory-leak-free and thread-leak-free?
I am not able to see any issue with executor or shutDownNow. Probably you are looking at different threads in your profiler.
Try this program which is similar to the one in your question and you can see the thread is no longer there after successful shutdown.
public class ExecutorShutdownTest {
private static ExecutorService executor;
private static AtomicLong executorThreadId = new AtomicLong(0);
public static void main(String[] args) {
// get thread MX bean
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// create an executor and start the task
executor = Executors.newSingleThreadExecutor(new TestThreadFactory());
LongRunnable runnable = new LongRunnable();
executor.submit(runnable);
// main thread: keep running for sometime
int count = 5;
while (count-- > 0) {
try {
Thread.sleep(1000);
System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace(
"\n", ""));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// main thread: stop the task
try {
runnable.close();
System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace("\n", ""));
} catch (Exception e) {
e.printStackTrace();
}
// main thread: run some more time to verify the executor thread no longer exists
count = 5;
while (count-- > 0) {
try {
Thread.sleep(1000);
System.out.println(String.valueOf(threadMXBean.getThreadInfo(executorThreadId.longValue())).replace("\r", "").replace("\n", ""));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class LongRunnable implements Runnable {
private volatile boolean isRunning = true;
#Override
public void run() {
while (isRunning) {
System.out.println("Running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//ignore
}
}
System.out.println("Stopped");
}
public void close() throws Exception {
System.out.println("Stopping");
isRunning = false;
executor.shutdownNow();
}
}
private static class TestThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
TestThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0) {
#Override protected void finalize() throws Throwable {
super.finalize();
// probably bad idea but lets see if it gets here
System.out.println("Executor thread removed from JVM");
}
};
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
executorThreadId.set(t.getId());
System.out.println("Executor thread created");
return t;
}
}
}
Here's a sample program using the single-thread Executor that manages to strand a thread so that the JVM can't shut down, but it only manages to do it by not calling shutdownNow:
import java.util.concurrent.*;
public class Exec {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new MyTask());
Thread.sleep(20000L);
// executor.shutdownNow();
int retryCount = 4;
while (!executor.isTerminated() && retryCount > 0) {
System.out.println("waiting for tasks to terminate");
Thread.sleep(500L);
retryCount -= 1;
}
}
}
class MyTask implements Runnable {
public void run() {
int count = 0;
try {
while (!Thread.currentThread().isInterrupted() && count < 10) {
Thread.sleep(1000L);
count += 1;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("all done");
}
}
The thread used by the executor has a separate life cycle from the task, this example shows how the task finishes but the thread goes on. Uncommenting the shutdownNow results in the executor's thread terminating. Otherwise the main thread sleeps for a while and exits, leaving the executor's thread hanging out, preventing the JVM from exiting.
My guess is that your close method isn't getting called and your executor never gets shut down. To get more useful answers please add a MVCE so that we can reproduce the problem.
Consider that with interruption there's no need to keep a reference to the Runnable to set the flag. As I read the question the task not finishing is not an issue here, but it would still be better to make the Runnable respond to interruption and lose the flag, just because having less things to keep track of is always an improvement.
I can suspend the thread with user input in console,but can't resume it again with user input.
I want to resume the thread when user gives input "n". Again it will start with prev state
please help folks.
Thanks.
import java.io.Console;
import java.util.Scanner;
class NewThread implements Runnable {
String name; // name of thread
Thread t;
boolean suspendFlag;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
suspendFlag = false;
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
// String username = scanner.nextLine();
try {
for(int i = 5000; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
//String username = scanner.nextLine();
// if(username.equals("y"))
// {
// mysuspend();
// }
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
void mysuspend() {
suspendFlag = true;
}
synchronized void myresume() {
suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob2 = new NewThread("One");
// System.out.println(username);
try { Scanner scanner = new Scanner(System.in);
String username = scanner.nextLine();
if(username.equals("y"))
{
Thread.interrupted();
// Thread.sleep(10000);
ob2.mysuspend();
System.out.println("Suspending thread One");
Thread.sleep(10000);
// ob2.myresume();
System.out.println("Resuming thread One");
}
if(username.equals("n"))
{
ob2.myresume();
}
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Your control flow is wrong.
You are reading input only once. If it is equal to y you are suspending the thread, but then you never go into the if statement that tests for n to resume the thread. I would do it like this:
public class Test {
public static void main(String args[]) {
NewThread ob2 = new NewThread("One");
Scanner scanner = new Scanner(System.in);
while(true) {
String username = scanner.nextLine();
if (username.equals("y")) {
Thread.interrupted();
// Thread.sleep(10000);
ob2.mysuspend();
System.out.println("Suspending thread One");
}
if (username.equals("n")) {
ob2.myresume();
System.out.println("Resuming thread One");
}
if (username.equals("q")) {
ob2.myresume();
break;
}
}
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
If the user enters "y" the thread will be suspended. If they enter "n" it will be resumed and if they enter "q" you will just break the loop and wait for the thread to finish.
1.. You are using methods wait() and notify() but you want to suspend and resume the thread. So it is not the right way. These methods are used to release any resource (synchronized) from one thread to make it available to some other thread and again give that resource back to same thread.
You should use only suspend() and resume() methods instead.
You cannot use wait() and notify() in your program.
2.. Try doing this in the following manner :
Create two threads. One which will get inputs from user and second which you want to suspend and resume.
According to the input of user call suspend and resume methods on second thread.
*In your code you are getting input from user only once. So once thread suspended is never resumed.
I believe that the main thread cannot die before the child thread. But is there any way to check that ? I wrote a simple program below. Can anyone prove it practically leaving theory aside ?
class childre extends Thread
{
public void run()
{
for( int i=0 ; i<10 ;i++)
{
System.out.println( " child " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ChildThreadb4main
{
/**
* #param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
System.out.println("main");
childre c1 = new childre();
c1.start();
for(int i=0;i<5;i++)
{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println( " child thread alive ? " + c1.isAlive());
}
}
After suggestion from James. I tried the following program.
public class MainChildDie {
public static void main(String ar[]){
final Thread mainThread = Thread.currentThread();
System.out.println("main run ");
new Thread(){
public void run(){
Thread childThread= Thread.currentThread();
for(int i=0; i<10;i++){
System.out.println( "child"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main alive " + mainThread.isAlive());
}
}.start();
}
}
From http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html :
The Java Virtual Machine continues to execute threads until either of
the following occurs:
The exit method of class Runtime has been called and the security
manager has permitted the exit operation to take place.
All threads
that are not daemon threads have died, either by returning from the
call to the run method or by throwing an exception that propagates
beyond the run method.
In your case, when the main thread dies, the JVM does not exit, because you still have the created threads running, and they're daemon by default, because of this:
The newly created thread is initially marked as being a daemon thread if and only if the thread creating it is currently marked as a daemon thread. The method setDaemon may be used to change whether or not a thread is a daemon.
Cite: http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#setDaemon(boolean)
While the code is executing, take a Full Thread dump and see what all Threads are active.
class AnotherClass {
public static void main(String arrp[]) throws Exception {
Thread t = new Thread() {
public void run() {
while (true) {
// do nothing
}
}
};
t.start();
//Sleep for 15 seconds
Thread.sleep(15000);
}
}
Compile and Execute it:
$ javac AnotherClass.java
$ java AnotherClass
Find the process:
$ ps -ef | grep AnotherClass
nikunj <<10720>> 10681 2 12:01:02 pts/9 0:04 java AnotherClass
nikunj 10722 10693 0 12:01:05 pts/6 0:00 grep Another
Take the Thread dump:
$ kill -3 <<10720>>
Output (excerpts):
"main" prio=10 tid=0x00039330 nid=0x1 waiting on condition [0xffbfe000..0xffbfe2a8]
at java.lang.Thread.sleep(Native Method)
at AnotherClass.main(AnotherClass.java:12)
"Thread-0" prio=10 tid=0x00a1b770 nid=0x12 runnable [0xadc7f000..0xadc7f970]
at AnotherClass$1.run(AnotherClass.java:7)
Take Another Thread dump (after 15 seconds):
$ kill -3 <<10720>>
New Output (excerpts):
"Thread-0" prio=10 tid=0x00a1b770 nid=0x12 runnable [0xadc7f000..0xadc7f970]
at AnotherClass$1.run(AnotherClass.java:7)
Conclusion:
main is gone.
Thread.currentThread().getThreadGroup().activeCount()
will return the active threads of a threadgroup of current thread default main
class childre extends Thread
{
public void run()
{
for( int i=0 ; i<10 ;i++)
{
System.out.println( " child " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getThreadGroup().activeCount());
}
}
You can use 'join' method to make sure that main thread waits till the child thread is completed.
childre c1 = new childre();
c1.start();
try {
c1.join();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
class Print implements Runnable
{
Thread thread, mainThread;
Print(Thread t)
{
mainThread = t;
thread = new Thread(this, "Thread");
thread.start();
}
#Override
public void run()
{
for(int i = 0; i < 5; i++)
{
System.out.println(thread.getName() + "\t" + (i+1));
try
{
Thread.sleep(1000);
}
catch(InterruptedException ie)
{
System.out.println("Interrupted Exception " + thread.getName());
}
System.out.println("Is main thread alive "+mainThread.isAlive());
}
}
}
public class ThreadOne
{
public static void main(String[] args)
{
Print p1 = new Print(Thread.currentThread());
System.out.println("Main Thread Ends");
}
}
The above code will show you that the main thread has completed execution while the newThread spawned still running.