java - 如何使用 java.util.concurrent 挂起线程?

标签 java multithreading java.util.concurrent

我到处都找过了。如何通过代码挂起/暂停它,直到我使用任何 java.util.concurrent 方法/对象将其唤醒?我有带有 run 方法的简单线程:

当我按下按钮时,它会停止然后启动,但问题是当我再次启动它时会出现异常。我希望它像在媒体播放器中一样播放/暂停。

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

完整的工作代码(有异常(exception)):

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();
        }
    }

}

最佳答案

我看到您想要一个按钮来启动和停止线程。所以基本上你需要在 actionPerformed() ,获取锁,查找事物的状态,操作状态,告诉等待实体某些事情发生了变化,然后释放所有的锁。

Runnable线程(由于缺少标签)应基本保持不变,但应检查 Condition在循环内以避免出现 signalAll() 的情况醒来和Condition still 并不是语义上的真或假。 ( signal()signalAll() 不能保证在锁释放后立即同步,因此可能已经发生了 2 次对 actionPerformed() 的调用)。

    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();
        }
    }

}

关于java - 如何使用 java.util.concurrent 挂起线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20921083/

相关文章:

java - 关于 websphere Thread Hung 的问题

java - 如何使用多线程测试任务性能?

android - MapView 上的 java.util.ConcurrentModificationException

java - UTF-8写入xml成功

java - 通过 Google App Engine servlet 上传 ZIP,并将内容保存到 Cloud Storage (Java)

java - StoredProcedureItemReader 和 JdbcCursorItemReader 的游标数据保留在 java 堆内存中还是数据库中

java - 如何使用线程观察器

java - 如何在 libgdx-InputProcess 中使用缩放功能?

c# - 在启动时设置线程生命周期

java - 为什么 java.util.concurrent.FutureTask 不可序列化