可以恢复线程但无法完全停止

时间:2015-02-18 05:20:39

标签: java multithreading

我终于能够在你们提出一些很好的建议之后让我的线程恢复,但我无法阻止它......它似乎仍然被锁定但是我无法让它优雅地停止。这是全班,所以你可以运行它。我很亲密......我想。我已经注释了我在跑步和停止方法中的尝试

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package treadmakestop;

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 *
 * @author brett
 */
public class WorkFile {

    public static void main(String[] args) {
        WorkFile workFile = new WorkFile();
    }

    public WorkFile() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
                }

                JFrame frame = new JFrame("TvCOnvert");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TvGui());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setSize(350, 100);
                frame.setResizable(false);
                frame.setVisible(true);
            }
        });
    }

    public class TvGui extends JPanel {

        private JProgressBar tvpb;
        private JButton startButton;
        private JButton cancelButton;
        private JButton exitButton;
        private Worker worker;
        private Thread t;
        public TvGui() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.BOTH;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            startButton = new JButton();

            startButton.setText("Start");
            gbc.insets = new Insets(10, 5, 0, 0);
            gbc.gridx = 1;
            gbc.gridy = 2;
            gbc.weightx = 0.5;
            add(startButton, gbc);

            cancelButton = new JButton();
            gbc.insets = new Insets(10, 0, 0, 0);
            gbc.gridx = 2;
            gbc.gridy = 2;
            gbc.weightx = 0.5;
            cancelButton.setText("Cancel");
            add(cancelButton, gbc);

            exitButton = new JButton();
            gbc.insets = new Insets(10, 0, 0, 5);
            gbc.gridx = 3;
            gbc.gridy = 2;
            gbc.weightx = 0.5;
            exitButton.setText("Exit");
            add(exitButton, gbc);

            tvpb = new JProgressBar();
            tvpb.setBorderPainted(true);
            tvpb.setStringPainted(true);
            gbc.insets = new Insets(5, 5, 0, 5);
            gbc.weightx = 1.0;
            gbc.weighty = 1.0;
            gbc.gridx = 1;
            gbc.gridy = 3;
            gbc.gridwidth = 3;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.anchor = GridBagConstraints.BASELINE;
            add(tvpb, gbc);
            tvpb.addChangeListener(new ChangeListener() {

                @Override
                public void stateChanged(ChangeEvent e) {
                    System.out.println(tvpb.getValue());
                    if (tvpb.getValue() >= 100) {
                        worker = null;
                    }
                }
            });

            tvpb.addPropertyChangeListener("value", new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                }
            });

            startButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (worker == null) {
                        worker = new Worker(tvpb);
                        t = new Thread(worker);
                        t.start();
                    }
                }
            });

            cancelButton.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    worker.pause();
                    tvpb.setIndeterminate(true);
                    int n = JOptionPane.showConfirmDialog(
                            null,
                            "Sure you want to delete this process?",
                            "Kill Operation",
                            JOptionPane.YES_NO_OPTION);

                    if (n == JOptionPane.YES_OPTION) {
                       worker.stop();

                       //t.interrupt();
                        //worker = null;
                        tvpb.setIndeterminate(false);
                        tvpb.setValue(0);
                    } else if (n == JOptionPane.NO_OPTION) {
                        tvpb.setIndeterminate(false);
                        worker.resume();
                    }

                }
            });

            exitButton.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            });
        }
    }

    public class Worker implements Runnable {
        TvGui gu = new TvGui();
        private ReentrantLock pauseLock;
        private Condition pauseCondition;
        private AtomicBoolean paused;

        private JProgressBar tvpg;

        public Worker(JProgressBar tvpg) {
            paused = new AtomicBoolean();
            pauseLock = new ReentrantLock();
            pauseCondition = pauseLock.newCondition();
            this.tvpg = tvpg;
        }

        public void pause() {
            paused.set(true);
        }

        public void resume() {
            paused.set(false);
            pauseLock.lock();
            try {
                pauseCondition.signal();
            } finally {
                pauseLock.unlock();
            }
        }

        public synchronized void stop(){
            try {
//            gu.t = null;
//            gu.t.interrupt();
            //Thread thr = Thread.currentThread();
           System.out.println("Thread name is:"+" "+gu.t.getName());
           Thread.currentThread().interrupt();
            } catch (Exception e) {
            }


        }
         private volatile boolean threadSuspended;
        @Override
        public void run() {

            Thread thisThread = Thread.currentThread();
        while ( gu.t == thisThread) {
            try {
                Thread.sleep(1);
                synchronized(this) {
                    while (threadSuspended && gu.t ==thisThread)
                        wait();
                }
            } catch (InterruptedException e){
            }

        }


            int times = 100_000;
            for (int i = 0; i <= times; i++) {
                checkPauseState();
                updateProgress(Math.round((i / (float) times) * 100f));
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ex) {
                }
            }

        }

        protected void checkPauseState() {
            while (paused.get()) {
                pauseLock.lock();
                try {
                    pauseCondition.await();

                } catch (Exception e) {
                } finally {
                    pauseLock.unlock();
                }
            }
        }

        protected void updateProgress(int progress) {
            if (EventQueue.isDispatchThread()) {
                tvpg.setValue(progress);
            } else {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        updateProgress(progress);
                    }
                });
            }
        }

        public boolean isPaused() {
            return paused.get();
        }

    }

}

1 个答案:

答案 0 :(得分:2)

除非您实际检查当前线程的intrrupted状态,否则中断它将无效...

相反,您可以使用另一个AtomicBoolean值来指示线程是否应该继续执行它的工作,例如

public class Worker implements Runnable {
    //...
    private AtomicBoolean keepRunning;

    public Worker(JProgressBar tvpg) {
        //...
        keepRunning = new AtomicBoolean(true);
        //...
    }
    //...

    public synchronized void stop() {
        keepRunning.set(false);
        // Make sure the thread isn't currently
        // paused, otherwise it will never exit...
        resume();
    }

    //...

    @Override
    public void run() {

        System.out.println("Runnable has started");

        int times = 100_000;
        int i = 0;
        while (i < times && keepRunning.get()) {
            checkPauseState();
            updateProgress(Math.round((i / (float) times) * 100f));
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
            }
            i++;
        }

        System.out.println("Runnable has exited");

    }

我们在run方法中更改循环以适应新的退出条件......

for (int i = 0; i < times && keepRunning.get(); i++) {
    checkPauseState();
    updateProgress(Math.round((i / (float) times) * 100f));
    try {
        Thread.sleep(1);
    } catch (InterruptedException ex) {
    }
}

完整的事情......

public class Worker implements Runnable {

    private ReentrantLock pauseLock;
    private Condition pauseCondition;
    private AtomicBoolean paused;
    private AtomicBoolean keepRunning;

    private JProgressBar tvpg;

    public Worker(JProgressBar tvpg) {
        paused = new AtomicBoolean();
        keepRunning = new AtomicBoolean(true);
        pauseLock = new ReentrantLock();
        pauseCondition = pauseLock.newCondition();
        this.tvpg = tvpg;
    }

    public void pause() {
        paused.set(true);
    }

    public void resume() {
        paused.set(false);
        pauseLock.lock();
        try {
            pauseCondition.signal();
        } finally {
            pauseLock.unlock();
        }
    }

    public synchronized void stop() {
        keepRunning.set(false);
        resume();
    }

    @Override
    public void run() {

        System.out.println("Runnable has started");

        int times = 100_000;
        int i = 0;
        while (i < times && keepRunning.get()) {
            checkPauseState();
            updateProgress(Math.round((i / (float) times) * 100f));
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
            }
            i++;
        }

        System.out.println("Runnable has exited");

    }

    protected void checkPauseState() {
        while (paused.get()) {
            pauseLock.lock();
            try {
                pauseCondition.await();

            } catch (Exception e) {
            } finally {
                pauseLock.unlock();
            }
        }
    }

    protected void updateProgress(int progress) {
        if (EventQueue.isDispatchThread()) {
            tvpg.setValue(progress);
        } else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    updateProgress(progress);
                }
            });
        }
    }

    public boolean isPaused() {
        return paused.get();
    }

}

另一个解决方案是获得state值,该值确定Worker类的当前值

public static class Worker implements Runnable {

    public enum State {
        RUNNING,
        PAUSED,
        NOT_STARTED,
        STOPPPED,
        COMPLETED;
    }

    private volatile State state = State.NOT_STARTED;

这为您提供了有关Worker当前状态的更多信息,以及有关如何完成(自然完成或是否已停止)的信息,例如......

public static class Worker implements Runnable {

    public enum State {
        RUNNING,
        PAUSED,
        NOT_STARTED,
        STOPPPED,
        COMPLETED;
    }

    private volatile State state = State.NOT_STARTED;

    private ReentrantLock pauseLock;
    private Condition pauseCondition;

    private JProgressBar tvpg;

    public Worker(JProgressBar tvpg) {
        pauseLock = new ReentrantLock();
        pauseCondition = pauseLock.newCondition();
        this.tvpg = tvpg;
    }

    public void pause() {
        if (state == State.RUNNING) {
            state = State.PAUSED;
        }
    }

    public void resume() {
        if (state == State.PAUSED || state == State.STOPPPED) {
            if (state == State.PAUSED) {
                state = State.RUNNING;
            }
            pauseLock.lock();
            try {
                pauseCondition.signal();
            } finally {
                pauseLock.unlock();
            }
        }
    }

    public synchronized void stop() {
        state = State.STOPPPED;
        resume();
    }

    @Override
    public void run() {

        state = State.RUNNING;
        System.out.println("Runnable has started");

        int times = 100_000;
        for (int i = 0; i < times && state != State.STOPPPED; i++) {
            checkPauseState();
            updateProgress(Math.round((i / (float) times) * 100f));
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
            }
        }

        if (state != State.STOPPPED) {
            state = State.COMPLETED;
        }

        System.out.println("Runnable has exited");

    }

    protected void checkPauseState() {
        while (state == State.PAUSED) {
            pauseLock.lock();
            try {
                pauseCondition.await();
            } catch (Exception e) {
            } finally {
                pauseLock.unlock();
            }
        }
    }

    protected void updateProgress(int progress) {
        if (EventQueue.isDispatchThread()) {
            tvpg.setValue(progress);
        } else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    updateProgress(progress);
                }
            });
        }
    }

    public boolean isPaused() {
        return state == State.PAUSED;
    }

    public boolean isRunning() {
        return state == State.RUNNING;
    }

    public boolean wasStopped() {
        return state == State.STOPPPED;
    }

    public boolean didComplete() {
        return state == State.COMPLETED;
    }

}

这取消了AtomicBoolean变量支持state变量...作为另一个想法