Question

I have looked everywhere. How to suspend/pause it by code until I call it to awake using any java.util.concurrentmethods/objects? I have simple Thread with run method:

When I press button it stops then starts but the problem is that I get exception when I start it again. I want it play/pause like in the media player.

Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException

Full working code(with exceptions):

import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

public class Window extends JFrame {
    ThreadPanel leftPanel, rightPanel;
    Thread leftThread, rightThread;

    public Window() {
        super("StopResume");
    }

    public void createGUI() {
        setLayout(new GridLayout());
        add(leftPanel = new ThreadPanel());
        add(rightPanel = new ThreadPanel());
        leftThread = new Thread(leftPanel);
        rightThread = new Thread(rightPanel);
        leftThread.start();
        rightThread.start();
        setSize(800, 600);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                int confirmed = JOptionPane.showConfirmDialog(null, "Zamknąć", "Potwierdzenie", JOptionPane.OK_CANCEL_OPTION);
                if (confirmed == JOptionPane.OK_OPTION) {
                    dispose();//tu podmienic kod
                    System.exit(1);
                }
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Window().createGUI();
            }
        });

    }

}

 import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class ThreadPanel extends JPanel implements Runnable {
    public static final String SUSPENDED = "GO", RUNNING = "SUSPEND";
    JTextArea txt;
    JButton ppButton;
    DateFormat dateFormat;
    Lock lock;
    Condition cond;
    boolean running;

    public ThreadPanel() {
        super();
        createGUI();
        dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        lock = new ReentrantLock();
        cond = lock.newCondition();
        running = true;
    }

    public void createGUI() {
        setLayout(new BorderLayout());
        JScrollPane jsp = new JScrollPane(txt = new JTextArea(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        add(jsp, BorderLayout.CENTER);
        add(ppButton = new JButton(RUNNING), BorderLayout.SOUTH);
        ppButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {

                System.out.println(1);
                if (running) {
                    running = false;
                    ppButton.setText(SUSPENDED);
                } else {
                    running = true;
                    ppButton.setText(RUNNING);
                    lock.unlock();
                }
                lock.lock();
                if (!running) {
                    cond.signalAll();
                }

                lock.unlock();

            }
        });
    }

    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (!running)
                    cond.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Calendar cal = Calendar.getInstance();
            txt.append("\n" + dateFormat.format(cal.getTime()));
            try {
                Thread.sleep((long) (Math.random() * 1001 + 500));
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(2);
            lock.unlock();
        }
    }

}
Was it helpful?

Solution

I see you want a button to start and stop the thread. So basically you need to in the actionPerformed(), acquire the lock, look up the state of things, manipulate the state, tell the waiting entity that something changed, and then release all your locks.

The Runnable thread (for lack of a label) should remain mostly unchanged but should check the Condition within a loop to avoid the case where your signalAll() wakes and the Condition still is not symenticly true or false. (signal() and signalAll() are not guaranteed to be sync right after the lock is released, so 2 calls to actionPerformed() may have happened already).

    public void createGUI() {
        setLayout(new BorderLayout());
        JScrollPane jsp = new JScrollPane(txt = new JTextArea(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        add(jsp, BorderLayout.CENTER);
        add(ppButton = new JButton(RUNNING), BorderLayout.SOUTH);
        ppButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // This is where we acquire the lock to safely look at the state
                lock.lock();
                System.out.println(1);
                // Manipulate the state
                if (running) {
                    running = false;
                    ppButton.setText(SUSPENDED);
                } else {
                    running = true;
                    ppButton.setText(RUNNING);
                }

                // Signal that this conditional changed (is either true or false now)
                cond.signalAll();
                // Release the lock so other entities can go forward
                lock.unlock();

            }
        });
    }

    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                // This should block until this condition is true with a loop
                while (!running)
                    cond.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Calendar cal = Calendar.getInstance();
            txt.append("\n" + dateFormat.format(cal.getTime()));
            // No need to sleep()
            System.out.println(2);
            lock.unlock();
        }
    }

}

OTHER TIPS

One way to do what I think you're asking for is to use a CyclicBarrier (from java.util.concurrent), parameterising it with two "parties".

The first thread to call await on the barrier will be suspended/blocked until a second thread also calls await, at which point both threads can proceed.

Here's a simple code sample:

import java.util.concurrent.CyclicBarrier;

public class Test {

    public static void main(String[] args) {

        // a barrier requiring two threads to call await before
        // any thread can proceed past the barrier
        final CyclicBarrier barrier = new CyclicBarrier(2);

        new Thread(){
            @Override
            public void run() {
                try {
                    // do some stuff
                    System.out.println("in thread, before the barrier");

                    // calling await blocks until two threads
                    // (this one and one other) have called await
                    barrier.await();

                    // do some more stuff
                    System.out.println("in thread, after the barrier");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

        try {
            System.out.println("main thread, before barrier");

            // calling await blocks until two threads
            // (this one and one other) have called await
            barrier.await();

            System.out.println("main thread, after barrier");
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top