多个线程一起工作

时间:2013-10-14 01:41:38

标签: java multithreading

我正在尝试编写使用线程的Java UI应用程序。线程1更新进度条,而线程2将字符串写入文件。但是,每当我尝试将它们组合在一起时,其中一个就无法工作。进度条会更新,但打印到文件失败或打印到文件成功,而进度条没有更新。有趣的是,如果我尝试System.out.println而不是buffer.append()。它工作正常。帮助我,伙计们

class updating implements Runnable {
    JProgressBar j;
    writing writing;

    updating(writing writing, JProgressBar j) {
        this.writing = writing;
        this.j = j;
    }

    @Override
    public void run() {
        while (true) {
            String message = writing.getMessage();
            Matcher matcher = Pattern.compile("\\d+").matcher(message);
            matcher.find();
            int i = Integer.valueOf(matcher.group());
            j.setValue(i);

            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(updating.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
public class writing implements Runnable{
    int i;
    BufferedWriter bw;

    writing(BufferedWriter bw, int i) {
        this.i = i;
        this.bw = bw;
    }
    private List messages = new ArrayList();
    private List messages1 = new ArrayList();

    @Override
    public void run() {
        while (true && i<=100) {
            putMessage(i);
            i++;
            System.out.println(getMessage1());

        }
    }

    public synchronized void putMessage(int i) {
        while (messages.size() >= 0x5) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        messages.add("Printing: " + i + "\r\n");

        notify();
    }

    public synchronized String getMessage() {
        while (messages.isEmpty()) {
            try {
                notify();
                wait();
            } catch (Exception e) {
            }
        }

        String message = (String) messages.remove(0);
        notify();
        messages1.add(message);
        return message;
    }

    public synchronized String getMessage1() {
        while (messages1.isEmpty()) {
            try {
                notify();
                wait();
            } catch (Exception e) {
            }
        }

        String message = (String) messages1.remove(0);
        notify();
        return message;
    }

    public boolean checking(){
        return messages.isEmpty();
    }
}


//UI
public class wThread extends javax.swing.JFrame {

    /** Creates new form wThread */
    public wThread() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jProgressBar1 = new javax.swing.JProgressBar();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jLabel1.setText("Status");

        jButton1.setText("Cancel");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("Start");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(65, 65, 65)
                .addComponent(jButton2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 68, Short.MAX_VALUE)
                .addComponent(jLabel1)
                .addGap(179, 179, 179))
            .addGroup(layout.createSequentialGroup()
                .addContainerGap(132, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(122, 122, 122))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jButton1)
                        .addGap(157, 157, 157))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(49, 49, 49)
                        .addComponent(jLabel1)
                        .addGap(18, 18, 18)
                        .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jButton1))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(32, 32, 32)
                        .addComponent(jButton2)))
                .addContainerGap(166, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        System.exit(0);
    }                                        

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        File f = new File("D:\\log.txt");
        BufferedWriter bf = null;
        try {
            bf = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
        } catch (FileNotFoundException ex) {
            Logger.getLogger(wThread.class.getName()).log(Level.SEVERE, null, ex);
        }

        jProgressBar1.setStringPainted(true);
        int i = 0;
        writing writer = new writing(bf, i);
        new Thread(writer).start();
        updating updater = new updating(writer, jProgressBar1);
        new Thread(updater).start();

        try {
            if(writer.checking()){
              bf.close();  
            }

        } catch (IOException ex) {
            Logger.getLogger(wThread.class.getName()).log(Level.SEVERE, null, ex);
        }

    }                                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new wThread().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JProgressBar jProgressBar1;
    // End of variables declaration                   
}

1 个答案:

答案 0 :(得分:0)

您只能从SwingThread触摸UI组件。从来没有任何其他线程。好消息是你需要一个单独的线程来完成Swing Thread的工作才能使它工作(比你当前的架构更少的资源)。这大致是你做的:

public void doLongRunningThing() {
    final JProgressBar bar = ....; // this comes from somewhere, maybe you create it or look it up.

    Thread workerThread = new Thread( new Runnable() {
        public void run() {
           try {
              for( int i = 0; i < words.length; i++ ) {
                  doSomeWorkOn( words[i] );
                  final int progress = i; // have to handle Java-ism
                  SwingUtilities.invokeLater( new Runnable() {
                     public void run() {
                         bar.setProgress( progress );
                     }
                  });
              }
           } finally {
              SwingUtilities.invokeLater( new Runnable() {
                 public void run() {
                     // todo clean up the UI like hide the dialog or hide progress bar, etc.
                 }
              });
           }
       }
    } );
    worker.start();
}

SwingUtilities.invokeLater()将一个runnable排队,以便从另一个线程在SwingThread上运行。因此,触摸排队的runnable中的swing组件是安全的。我会考虑使用ExecutorService而不是原始线程它实际上只会将线程实例化更改为:

// create a thread pool out in your program for background jobs
// then share that for all areas where you are doing background work, 
// network calls, etc.
ExecutorService executor = Executors.newFixedThreadPool(5);

public void doLongRunningThing() {
    final JProgressBar bar = ....; // this comes from somewhere, maybe you create it or look it up.

    executor.execute( new Runnable() {
        public void run() {
            ...same code as above...
        }
    } );        
}