0

I've got this programme of computing prime numbers. When pressing stop the programme stops computing the prime numbers but when I press GO i need the programme to continue with its computations, but I couldn't find out how can I start my thread again. I tried creating new instances of it but nothing happened. Here's my code:

public class PrimeApp1 extends JFrame {
protected JTextArea output;
protected JButton go;
protected JButton stop;
protected long counter = 2;
protected boolean stopComputation = false;
public boolean run = true;

protected boolean isPrime(long number) {
    long max = (long) Math.sqrt(number) + 1;
    for (long i = 2; i < max; i++) {
        if ((number % i) == 0) {
            return (false);
        }
    }
    return (true);
}

public class PrintPrimes extends Thread {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int primecount = 0;
        while (run == true) {
            if (isPrime(counter)) {
                primecount++;
                output.append(Long.toString(counter) + "\n");
                stop.setEnabled(true);
            }
            counter++;
        }
    }
}

public PrimeApp1() {
    super("Prime Numbers");
    final PrintPrimes print = new PrintPrimes();
    JPanel content = new JPanel();
    BorderLayout contentLayout = new BorderLayout();
    content.setLayout(contentLayout);

    output = new JTextArea();
    output.setEditable(false);
    JScrollPane scroller = new JScrollPane(output);
    content.add(scroller, BorderLayout.CENTER);

    JPanel buttonPane = new JPanel();
    FlowLayout buttonPaneLayout = new FlowLayout();
    buttonPane.setLayout(buttonPaneLayout);
    go = new JButton("Go");
    stop = new JButton("Stop");
    stop.setEnabled(false);
    buttonPane.add(go);
    buttonPane.add(stop);
    content.add(buttonPane, BorderLayout.SOUTH);

    go.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            print.start();
        }
    });

    stop.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            run = false;
        }
    });

    setContentPane(content);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(600, 600);
    setVisible(true);
}

public static void main(String[] args) {
    new PrimeApp1();
}

}

  • wait/notify should help you. – Juned Ahsan Oct 09 '14 at 00:46
  • 1
    What do you want, the thread to pause or the thread to terminate? There is quite a lot problematic in this area, your flags should be volatile, you might want to use other primitives like a Lock for parking. You should also not write to Swing controls from foreign threads. – eckes Oct 09 '14 at 01:00

3 Answers3

0

I think that your problem is that you are trying to start a thread that has already finished processing. You can only ever start a Thread once, see here for details.

Rather than starting the thread in the go action listener, perhaps you want to create a new Thread object in that ActionListener and start that.

Something like this:

go.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        PrintPrimes print = new PrintPrimes();
        print.start();
    }
});

Rather than creating a final Thread object in your constructor.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
PeterK
  • 1,697
  • 10
  • 20
0

That depends what you want to achieve. If you want to "Pause" then you should synchronize the running of the thread to the press of the button as @Junen suggested.

If you want to restart you could do something like this:

public class PrintPrimes extends Thread {

    @Override
    public void run() {
        run = true; //You started the thread, hence when you enter run() it is running.
        int primecount = 0;
        while (run) {
            if (isPrime(counter)) {
                primecount++;
                output.append(Long.toString(counter) + "\n");
                stop.setEnabled(true);
            }
            counter++;
        }
    }
}

Make print a class-object and change this:

go.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        print = new Thread(PrimeApp1.this);
        print.start();
    }
});
Muli Yulzary
  • 2,559
  • 3
  • 21
  • 39
0

If you're wanting to pause the threads, try something like the following. Note the run variable is volatile since it technically is being modified by the main thread.

I also noticed in your code example you are modifying the UI from the PrintPrimes thread. It is generally bad practice to update the user interface from a separately created thread.

How to update java GUI from Thread? provides some explanation around this issue.

How to Pause and Resume a Thread in Java from another Thread provides some additional information on stopping and resuming threads. In the run method, I used a similar implementation.

public class PrimeApp1 extends JFrame {
    protected JTextArea output;
    protected JButton go;
    protected JButton stop;
    protected boolean stopComputation = false;

    protected boolean isPrime(long number) {
        long max = (long) Math.sqrt(number) + 1;
        for (long i = 2; i < max; i++) {
            if ((number % i) == 0) {
                return (false);
            }
        }
        return (true);
    }

    public class PrintPrimes extends Thread {
        private int current = 2;
        private volatile boolean run = false;

        public PrintPrimes() {
        }

        public void run() {     
            while (true) {

                if (run == false) 
                    continue; // thread paused

                if (isPrime(current)) {
                    output.append(Long.toString(current) + "\n");                
                }
                current++;
            }
        }

        public void stopCount() {
            run = false;
        }

        public void startCount() {
            if (!run) {

                if (current == 2)
                    start(); // start initial thread 

                run = true;
            }
        }

    }

    public PrimeApp1() {
        super("Prime Numbers");
        final PrintPrimes print = new PrintPrimes();
        JPanel content = new JPanel();
        BorderLayout contentLayout = new BorderLayout();
        content.setLayout(contentLayout);

        output = new JTextArea();
        output.setEditable(false);
        JScrollPane scroller = new JScrollPane(output);
        content.add(scroller, BorderLayout.CENTER);

        JPanel buttonPane = new JPanel();
        FlowLayout buttonPaneLayout = new FlowLayout();
        buttonPane.setLayout(buttonPaneLayout);
        go = new JButton("Go");
        stop = new JButton("Stop");
        stop.setEnabled(false);
        buttonPane.add(go);
        buttonPane.add(stop);
        content.add(buttonPane, BorderLayout.SOUTH);

        go.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                go.setEnabled(false);
                stop.setEnabled(true);
                print.startCount();
            }
        });

        stop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                stop.setEnabled(false);
                go.setEnabled(true);
                print.stopCount();
            }
        });

        setContentPane(content);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 600);
        setVisible(true);
    }

    public static void main(String[] args) {
        new PrimeApp1();
    }
    }
Community
  • 1
  • 1
tjg184
  • 4,508
  • 1
  • 27
  • 54