1

I am creating a Swing application. It contains a JFrame, inside JFrame, I added a JButton to start and stop some tasks. I am using the same JButton to start and stop the tasks which are threads and executed by ExecutorService.

While clicking on the Start button, threads will be executed and the button label will be changed to Stop, while clicking on the Stop button will stop all threads (I have done this using ExecutorService shutdownNow() method) and the button label will be again changed to Start, but the applicaiton will not be closed. Now, if I click Start button again, applicaion gets hanged, the threads are not restarted from the beginning.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MultipleThreads {
    public static ExecutorService executor = Executors.newFixedThreadPool(4);

    public static void main(String[] args) {
        JFrame frame = new JFrame("Stop Thread");
        frame.setSize(200,200);
        frame.setLocationRelativeTo(null);
        frame.setLayout(null);
        JPanel panel = new JPanel();
        panel.setBounds(5,5,150,150);
        panel.setLayout(null);
        JButton btn = new JButton("Start");
        btn.setBounds(10,10,80,25);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (btn.getText().equals("Start")) {
                    btn.setText("Stop");
                    MultipleThreads2 runThreads = new MultipleThreads2();
                    runThreads.runThreadMethod();
                } else if (btn.getText().equals("Stop")) {
                    try {
                        if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                            executor.shutdownNow();
                        } 
                    } catch (InterruptedException e) {
                        executor.shutdownNow();
                    }

                    btn.setText("Start");
                }
            }
        });
        panel.add(btn);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

class MultipleThreads2 {
    public volatile boolean flag = true;

    public void stopRunning() {
        flag = false;
    }

    public MultipleThreads2() {
        while (flag) {
            try {
                MultipleThreads.executor.submit(t1);
                MultipleThreads.executor.submit(t2);
                flag = false;
                System.out.println(t1.isAlive());
            } catch (Exception e) {

            }
        }
    }

    public void runThreadMethod() {
        flag = true;
        while (flag) {
            try {
                MultipleThreads.executor.submit(t3);
                MultipleThreads.executor.submit(t4);
                    flag = false;
            } catch (Exception e) {

            }
        }
    }

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t1 Thread");
                    Thread.sleep(1000);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t2 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t3 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t3 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t4 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t4 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });
}

Expected: While clicking on Start button for the second time should restart all the threads from the beginning.

AbiSaran
  • 2,538
  • 3
  • 9
  • 15
  • Unrelated: *never* ever go with empty catch blocks. At least print the exceptions. You really want to understand when your code throws up for some reason. You are *learning* how things work, so be willing to look into surprising exceptions. And even later on, when you really know what you are doing, ignoring exceptions is really bad practice. – GhostCat May 07 '19 at 08:23

1 Answers1

1

Here:

public static ExecutorService executor = Executors.newFixedThreadPool(4);

You are creating that thread pool once. Later on, you are calling

executor.shutdownNow();

In other words: you are starting your car, and at some point, you stop the car, you get out, and you set it on fire. Then you ask yourself: "ok, how can I use that car to drive home?". Well, you can't. You just set it on fire.

Same thing here: when you shutdown the service, it is gone.

Long story short, a simple (not necessarily ideal) solution would be to do:

public static ExecutorService executor = null;

and later on:

if (executor == null) 
  executor = Executors.newFixedThreadPool(4);

and

executor.shutdownNow();
executor = null;

In other words: you drive with your car, you set it on fire, and then you buy a new one, to make another drive, before setting that on fire.

Of course, that approach of setting to null and checking for that could lead to various problems. It would be a bit better to do:

  executor.shutdownNow();
  executor = Executors.newFixedThreadPool(4);

Meaning: instead of leaving the executor around as null, you simply create a new instance, as soon as the "last one" was told to shutdown. So, theoretically, whenever the executor gets used to submit tasks OR it gets shutdown, you are talking to a currently "valid" instance.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Clear and great explanation. – AbiSaran May 07 '19 at 10:42
  • Also, I have another question, in the above code, i want to execute the threads t1 and t2 first, once these 2 threads are completed then t3 and t4 thread should start the execution. How can I achieve this? Could you please help me? – AbiSaran May 07 '19 at 10:46
  • @AbiSaran Please keep in mind that stackoverflow is like "one question, one/more answers". So coming back with comments asking different questions isn't really how things work here. You could consider asking a new question for that. But having said that ... – GhostCat May 07 '19 at 11:02
  • You might look at https://stackoverflow.com/questions/7939257/wait-until-all-threads-finish-their-work-in-java for example. It really depends: do you want for threads to **complete** (then you could/should use things like wait()/notify()), or is it more about "tasks" being completed? Long story short: these are very basic patterns, and you can find a ton of good resources out there. So my suggestion: do some (net) research first, and when you are still unsure, or you have written code that doesnt work, write up a new question here. – GhostCat May 07 '19 at 11:03
  • Maybe, we should talk about the fundamental error of creating `Thread` instances and submitting them to an `ExecutorService`, instead of just submitting the `Runnable`s, too. Further, there is no point in calling `awaitTermination` when there was no preceding shutdown call. And generally, the right approach is to keep the `Future`s returned by `submit` and cancel those, then, there is no need for defeating the actual purpose of a thread pool by shutting it down and creating a new one. – Holger May 10 '19 at 09:56
  • @Holger Sure, we could talk about all these things. Yeah, many things to be considered here ... – GhostCat May 10 '19 at 10:36