Pausing and resuming Threads can be easily implemented by using synchronized blocks.

Synchronized blocks in Java use Objects to act as a lock that is able to control what can be run. Synchronized methods use this as the monitor for synchronization.

By using Object.wait(), a block's execution can be stopped until the lock calls notify() or notifyAll(). Object.notify() causes only one Thread to be woken up from its waiting state, while Object.notifyAll() causes every Thread waiting on the monitor to resume execution.

See the API for more details on the difference between these.

The Java tutorial on synchronization is thorough, but more complex than necessary. This is a simple introduction to synchronization.

The following code listing demonstrates pausing and resuming threads with a button:

import javax.swing.*;

public class PauseResume {
    private JFrame frame = new JFrame("PauseResume");
    private JButton button = new JButton("Start");
    private JTextArea textArea = new JTextArea(5,20);
    
    private Object lock = new Object();
    private volatile boolean paused = true;
    
    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PauseResume();
            }
        });
    }
    
    public PauseResume() {
        counter.start();
        button.addActionListener(pauseResume);
        
        textArea.setLineWrap(true);
        frame.add(button,java.awt.BorderLayout.NORTH);
        frame.add(textArea,java.awt.BorderLayout.SOUTH);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private Thread counter = new Thread(new Runnable() {
        @Override
        public void run() {
            while(true) {
                work();
            }
        }
    });
    
    private void work() {
        for(int i = 0;i < 10;i++) {
            allowPause();
            write(Integer.toString(i));
            sleep();
        }
        done();
    }
    
    private void allowPause() {
        synchronized(lock) {
            while(paused) {
                try {
                    lock.wait();
                } catch(InterruptedException e) {
                    // nothing
                }
            }
        }
    }
    
    private java.awt.event.ActionListener pauseResume =
        new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                    paused = !paused;
                    button.setText(paused?"Resume":"Pause");
                synchronized(lock) {
                    lock.notifyAll();
                }
            }
        };
    
    private void sleep() {
        try {
            Thread.sleep(500);
        } catch(InterruptedException e) {
            // nothing
        }
    }
    
    private void done() {
        button.setText("Start");
        paused = true;
    }
    
    public void write(String str) {
        textArea.append(str);
    }
}

Because threads can't be started more than once, the Thread here loops continuously. The allowPause() method contains a synchronized block using the Object lock as the monitor. The ActionListener for the start/pause/resume button uses the same lock, so it can call notifyAll() to wake up any synchronized blocks in execution with the same lock as the monitor.

When the user pauses the program, execution in the allowPause() method can enter the while loop and suspend the Thread. If the thread is interrupted for any reason other than being unpaused, it continues sleeping because of the while loop.