2013-10-14 68 views
0

我正在尝试编写使用线程的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

我会用的BlockingQueue,如果没有一个ExecutorService,几乎所有的队列/线程处理代码就会消失。 –

+0

您违反了Swing的单线程规则。看看[并发在Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)了解更多详情 – MadProgrammer

回答

0

你只能触摸SwingThread中的UI组件。从来没有从任何其他线程。好消息是,您只需要一个线程完成摆脱Swing线程的工作,以使其工作(资源少于当前架构)。这大概是你做什么:

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()排队一个可运行对SwingThread从另一个线程中运行。因此,触摸排队的可运行内部的摆动组件是安全的。我会考虑使用一个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... 
     } 
    });   
}