如何同步两个线程,以便它们在Java

时间:2017-03-05 02:41:43

标签: java multithreading jprogressbar

我试图实现一个进度条,用于确定Java中另一个线程的(近似)完成百分比。现在我有两个线程同时运行,但我不确定如何链接到另一个线程。我需要它从0开始,到另一个朋友完成时,我希望进度条说100。这是我到目前为止。我几乎整天都在寻找解决方案,但似乎找不到任何东西。建议?

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileSystemView;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.*;
import java.io.File;

public class ProgressBarTest extends JFrame {
    JButton browse, search;
    JTextField directory;
    JProgressBar progressBar;
    File file;
    JList<File> results;
    JScrollPane scrollPane;

    // Launch the app
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new ProgressBarTest();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    // Create the app
    private ProgressBarTest() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("We are testing the JProgressBar");

        browse = new JButton("Browse");
        browse.setActionCommand("browse");
        browse.addActionListener(new ButtonListener());

        search = new JButton("Search");
        search.setActionCommand("search");
        search.addActionListener(new ButtonListener());

        directory = new JTextField(20);
        directory.setEnabled(false);

        file = new File(System.getProperty("user.home"));
        results = new JList<File>(file.listFiles());
        results.setCellRenderer(new MyCellRenderer());
        results.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        results.setVisibleRowCount(-1);

        scrollPane = new JScrollPane(results, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setPreferredSize(new Dimension(408, 100));

        progressBar = new JProgressBar(0,100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);

        JPanel panel1 = new JPanel();
        panel1.add(browse);
        panel1.add(directory);
        panel1.add(search);

        JPanel panel2 = new JPanel();
        panel2.add(scrollPane);

        JPanel panel3 = new JPanel();
        panel3.add(progressBar);

        this.add(panel1, BorderLayout.PAGE_START);
        this.add(panel2, BorderLayout.CENTER);
        this.add(panel3, BorderLayout.PAGE_END);

        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    private class MyCellRenderer extends DefaultListCellRenderer {
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            JLabel l = (JLabel)c;
            File f = (File)value;
            l.setText(f.getName());
            l.setPreferredSize(new Dimension(130, 20));
            l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
            l.setBorder(new EmptyBorder(3,3,3,3));

            return l;
        }
    }

    private class ButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            if(event.getActionCommand().equals("browse")) {
                JFileChooser chooser = new JFileChooser(System.getProperty("user.home"));
                chooser.setDialogTitle("Search what?");
                chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                chooser.showOpenDialog(null);

                directory.setText(chooser.getSelectedFile().getPath());
            } else if (event.getActionCommand().equals("search")) {
                FileThread ft = new FileThread();
                ft.start();

                ProgressBarThread pbt = new ProgressBarThread();
                pbt.start();

            }
        }
    }

    private class FileThread extends Thread {
        public void run() {
            file = new File(directory.getText().trim());
            results.setListData(file.listFiles());
        }
    }

    private class ProgressBarThread extends Thread {
        public void run() {
            for (int i = 0; i <= 100; i++) {
                progressBar.setValue(i);
                progressBar.setString(Integer.toString(i));
                try {
                    Thread.sleep(50);
                } catch(InterruptedException err) {
                    err.printStackTrace();
                }
            }
        }
    }
}

我知道我必须用确定第一个线程的百分比/时间的东西取出for循环。只是不确定这是怎么做的。

1 个答案:

答案 0 :(得分:0)

关键是

  1. 确保您尝试将任何和所有长时间运行的处理卸载到后台线程
  2. 避免进行Swing调用,尤其是在Swing事件线程以外的任何线程上进行突变Swing调用。
  3. 如果您无法量化需要完成的工作量并且无法通过后台任务通知已完成此项工作的百分比,请考虑将JProgressBar设置为不确定。
  4. 否则使用确定的进度条,但让后台任务以间接方式通知Swing GUI进度,通常通过带有回调的侦听器(如PropertyChangeListener)完成。
  5. 例如,我尝试使用下面的代码执行上述操作,一个递归列出目录和子目录中的文件,但我还不是100%满意。它使用所选目录的主子目录的完成,但它以某种方式冻结GUI,这意味着我仍然在事件线程上调用cpu或占用时间的代码。这里需要做更多的工作......

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.File;
    import java.io.FileFilter;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.*;
    import javax.swing.border.EmptyBorder;
    import javax.swing.filechooser.FileSystemView;
    
    @SuppressWarnings("serial")
    public class ProgressBarTest2 extends JPanel {
        private static final int PREF_W = 420;
        private static final int PREF_H = 200;
        private JProgressBar progressBar = new JProgressBar(0, 100);
        private DefaultListModel<File> fileListModel = new DefaultListModel<>();
        private JList<File> results = new JList<>(fileListModel);
        private Action browseAction = new BrowseAction("Browse", KeyEvent.VK_B);
        private JButton browseButton = new JButton(browseAction);
    
        public ProgressBarTest2() {
            progressBar.setValue(0);
            progressBar.setStringPainted(true);
    
            results.setCellRenderer(new MyCellRenderer());
            results.setLayoutOrientation(JList.HORIZONTAL_WRAP);
            results.setVisibleRowCount(-1);
            JScrollPane scrollPane = new JScrollPane(results);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
            scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    
            JPanel topPanel = new JPanel();
            topPanel.add(browseButton);
    
            setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
            setLayout(new BorderLayout(3, 3));
            add(topPanel, BorderLayout.PAGE_START);
            add(scrollPane, BorderLayout.CENTER);
            add(progressBar, BorderLayout.PAGE_END);
        }
    
        @Override
        public Dimension getPreferredSize() {
            Dimension superSz = super.getPreferredSize();
            if (isPreferredSizeSet()) {
                return superSz;
            }
            int prefW = Math.max(superSz.width, PREF_W);
            int prefH = Math.max(superSz.height, PREF_H);
            return new Dimension(prefW, prefH);
        }
    
        public void workerIsDone() {
            browseAction.setEnabled(true);
        }
    
    
        private class BrowseAction extends AbstractAction {
            private FileWorker fileWorker;
    
            public BrowseAction(String name, int mnemonic) {
                super(name);
                putValue(MNEMONIC_KEY, mnemonic);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                setEnabled(false);
                progressBar.setValue(0);
    
                JFileChooser chooser = new JFileChooser(System.getProperty("user.home"));
                chooser.setDialogTitle("Search what?");
                chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int choice = chooser.showOpenDialog(null);
                if (choice != JFileChooser.APPROVE_OPTION) {
                    return;
                }
    
                File file = chooser.getSelectedFile();
                if (file == null) {
                    return;
                }
                if (!file.isDirectory()) {
                    file = file.getParentFile();
                    if (file == null || !file.isDirectory()) {
                        return;
                    }
                }
    
                fileWorker = new FileWorker(file);
                fileWorker.addPropertyChangeListener(new FileWorkerListener());
                fileWorker.execute();
            }
        }
    
        class FileWorkerListener implements PropertyChangeListener {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("progress".equals(evt.getPropertyName())) {
                    int progress = (int) evt.getNewValue();
                    progressBar.setValue(progress);
                } else if ("state".equals(evt.getPropertyName())) {
                    if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
                        workerIsDone();
                        FileWorker worker = (FileWorker) evt.getSource();
                        try {
                            worker.get();
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        class FileWorker extends SwingWorker<Void, File> {
            private MyFileFilter dirFilter = new MyFileFilter(true);
            private MyFileFilter nonDirFilter = new MyFileFilter(false);
            private File file;
    
            public FileWorker(File file) {
                this.file = file;
            }
    
            @Override
            protected Void doInBackground() throws Exception {
                fileListModel.clear();
                File[] files = file.listFiles(nonDirFilter);
                for (File file2 : files) {
                    publish(file2);
                }
                File[] dirs = file.listFiles(dirFilter);
                for (int i = 0; i < dirs.length; i++) {
                    recurseThruDirs(dirs[i]);
                    int prog = (100 * i) / dirs.length;
                    setProgress(prog);
                }
    
                setProgress(100);
                return null;
            }
    
            private void recurseThruDirs(File file) {
                if (file == null) {
                    return;
                }
                File[] files = file.listFiles(nonDirFilter);
                if (files != null && files.length > 0) {
                    for (File file2 : files) {
                        publish(file2);
                    }
                }
                File[] dirs = file.listFiles(dirFilter);
                if (dirs != null && dirs.length > 0) {
                    for (int i = 0; i < dirs.length; i++) {
                        recurseThruDirs(dirs[i]);
                    }
                }
            }
    
            @Override
            protected void process(List<File> chunks) {
                for (File file : chunks) {
                    fileListModel.addElement(file);
                }
            }
        }
    
        class MyFileFilter implements FileFilter {
            private boolean directory;
    
            public MyFileFilter(boolean directory) {
                this.directory = directory;
            }
    
            @Override
            public boolean accept(File pathname) {
                return directory == pathname.isDirectory();
            }
        }
    
        private class MyCellRenderer extends DefaultListCellRenderer {
            public Component getListCellRendererComponent(JList<?> list, Object value, int index,
                    boolean isSelected, boolean cellHasFocus) {
                Component c = super.getListCellRendererComponent(list, value, index, isSelected,
                        cellHasFocus);
                JLabel l = (JLabel) c;
                File f = (File) value;
                l.setText(f.getName());
                l.setPreferredSize(new Dimension(130, 20));
                l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
                l.setBorder(new EmptyBorder(3, 3, 3, 3));
    
                return l;
            }
        }
    
        private static void createAndShowGui() {
            ProgressBarTest2 mainPanel = new ProgressBarTest2();
    
            JFrame frame = new JFrame("ProgressBarTest2");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }