2011-08-13 7 views
18

Tôi chơi với đa luồng cho SwingWorker bằng cách sử dụng Executor, và tôi ở đó do nhầm lẫn xác định các phần tử sai từ Vector, trông giống như mã này khá bỏ qua yếu tố đó trong Vector không tồn tạiKhông thể nhận được ArrayIndexOutOfBoundsException từ tương lai <?> và SwingWorker nếu chủ đề bắt đầu Executor

câu hỏi của tôi -> làm thế nào để/có thể bắt ngoại lệ này (s) một số cách

đầu ra đơn giản

run: 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
BUILD SUCCESSFUL (total time: 11 seconds) 

bởi bỏ ghi chú

//changeTableValues1(); // un-comment for get ArrayIndexOutOfBoundsException 

mọi thứ đều đúng, tôi nhận được ArrayIndexOutOfBoundsException và đầu ra là

run: 
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2 
     at java.util.Vector.get(Vector.java:694) 
     at KondorExport.Util.Help.Table.TableWithExecutor.changeTableValues1(TableWithExecutor.java:70) 
     at KondorExport.Util.Help.Table.TableWithExecutor.access$100(TableWithExecutor.java:18) 
     at KondorExport.Util.Help.Table.TableWithExecutor$2.actionPerformed(TableWithExecutor.java:61) 
     at javax.swing.Timer.fireActionPerformed(Timer.java:271) 
     at javax.swing.Timer$DoPostEvent.run(Timer.java:201) 
     at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) 
     at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) 
     at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) 
     at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) 
     at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) 
     at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) 
     at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) 
     at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
BUILD SUCCESSFUL (total time: 10 seconds) 

từ mã

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.util.List; 
import java.util.Vector; 
import java.util.concurrent.Executor; 
import java.util.concurrent.Executors; 
import javax.swing.*; 
import javax.swing.table.*; 

public class TableWithExecutor extends JFrame { 

    private static final long serialVersionUID = 1L; 
    private String[] columnNames = {"Narrative", "Description"}; 
    private Object[][] data = {{"About", "About"}, {"Add", "Add"}}; 
    private JTable table; 
    private Executor executor = Executors.newCachedThreadPool(); 
    private Timer timerRun; 
    private int delay = 3000; 
    private Vector<String> fwDeals; 
    private Vector<String> fwDeals1; 

    public TableWithExecutor() { 
     DefaultTableModel model = new DefaultTableModel(data, columnNames); 
     table = new JTable(model) { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public Class getColumnClass(int column) { 
       return getValueAt(0, column).getClass(); 
      } 
     }; 
     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     JScrollPane scrollPane = new JScrollPane(table); 
     add(scrollPane, BorderLayout.CENTER); 
     prepareStartShedule(); 
    } 

    private void prepareStartShedule() { 
     timerRun = new javax.swing.Timer(delay, startCycle()); 
     timerRun.setRepeats(true); 
     timerRun.start(); 
    } 

    private Action startCycle() { 
     return new AbstractAction("Start Shedule") { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       executor.execute(new TableWithExecutor.MyTask("StartShedule")); //non on EDT 
       //changeTableValues1(); // un-comment for get ArrayIndexOutOfBoundsException 
      } 
     }; 
    } 

    private void changeTableValues1() { 
     fwDeals1 = new Vector<String>(); 
     fwDeals1.add("First"); // ElementAt(0) 
     fwDeals1.add("Second");// ElementAt(1) 
     checkDealsInDb1(fwDeals1.get(1), fwDeals1.get(2)); 
    } 

    private void checkDealsInDb1(String Str, String Str1) { 
     table.getModel().setValueAt(Str, 0, 1); 
     table.getModel().setValueAt(Str1, 1, 1); 
    } 

    private void changeTableValues() { 
     fwDeals = new Vector<String>(); 
     fwDeals.add("First"); // ElementAt(0) 
     fwDeals.add("Second");// ElementAt(1) 
     checkDealsInDb(fwDeals.get(1), fwDeals.get(2)); 
    } 

    private void checkDealsInDb(String Str, String Str1) { 
     table.getModel().setValueAt(Str, 0, 1); 
     table.getModel().setValueAt(Str1, 1, 1); 
    } 

    public static void main(String[] args) { 
     TableWithExecutor frame = new TableWithExecutor(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.setLocation(150, 150); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private class MyTask extends SwingWorker<Void, Integer> { 

     private String str; 
     private String namePr; 

     MyTask(String str) { 
      this.str = str; 
      addPropertyChangeListener(new SwingWorkerCompletionWaiter(str, namePr)); 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      if (str.equals("StartShedule")) { 
       changeTableValues(); 
      } 
      return null; 
     } 

     @Override 
     protected void process(List<Integer> progress) { 
     } 

     @Override 
     protected void done() { 
      if (str.equals("StartShedule")) { 
      } 
     } 
    } 

    private class SwingWorkerCompletionWaiter implements PropertyChangeListener { 

     private String str; 
     private String namePr; 

     SwingWorkerCompletionWaiter(String str, String namePr) { 
      this.str = str; 
      this.namePr = namePr; 
     } 

     SwingWorkerCompletionWaiter(String namePr) { 
      this.namePr = namePr; 
     } 

     @Override 
     public void propertyChange(PropertyChangeEvent event) { 
      if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { 
       System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); 
      } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) { 
       System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue()); 
      } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) { 
       System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); 
      } else { 
       System.out.println("SomeThing Wrong happends with Thread Status with Name :" + str); 
      } 
     } 
    } 
} 

EDIT:

thêm vào lại ném từ Future # get() trong done() phương pháp (bởi @takteek đề xuất tuyệt vời)

@Override 
    protected void done() { 
     if (str.equals("StartShedule")) { 
      try { 
       get(); 
       //errLabel.setText(String.valueOf(get())); 
      } catch (InterruptedException ie) { 
       ie.printStackTrace(); 
      } catch (ExecutionException ee) { 
       ee.printStackTrace(); 
      }catch (IllegalStateException is) { 
       is.printStackTrace(); 
      } 
     } 
    } 

nhưng sản lượng vẫn còn và chỉ Got exception, sẽ rất khó có thể nhận được bất kỳ ngoại lệ (s) từ BlackBox này

run: 
Got exception 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
Got exception 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
Got exception 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
Got exception 
Thread Status with Name :StartShedule, SwingWorker Status is STARTED 
Thread Status with Name :StartShedule, SwingWorker Status is DONE 
BUILD SUCCESSFUL (total time: 13 seconds) 

Trả lời

15

Tôi không chắc nó có thêm nhiều hay không, nhưng tôi đã nhận được mong đợi Caused by bằng cách sử dụng biến thể của answer của takteek được hiển thị bên dưới. Tôi chạy nó từ dòng lệnh để đảm bảo IDE không phải là "giúp đỡ".

 
$ java -cp build/classes TableWithExecutor 
StartShedule: PENDING -> STARTED 
java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2 
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222) 
    at java.util.concurrent.FutureTask.get(FutureTask.java:83) 
    at javax.swing.SwingWorker.get(SwingWorker.java:582) 
    at TableWithExecutor$MyTask.done(TableWithExecutor.java:103) 
    at javax.swing.SwingWorker$5.run(SwingWorker.java:717) 
    at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:814) 
    at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:95) 
    at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:824) 
    at javax.swing.Timer.fireActionPerformed(Timer.java:291) 
    at javax.swing.Timer$DoPostEvent.run(Timer.java:221) 
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:677) 
    at java.awt.EventQueue.access$000(EventQueue.java:85) 
    at java.awt.EventQueue$1.run(EventQueue.java:638) 
    at java.awt.EventQueue$1.run(EventQueue.java:636) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:647) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) 
Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 2 
    at java.util.Vector.get(Vector.java:694) 
    at TableWithExecutor.changeTableValues(TableWithExecutor.java:64) 
    at TableWithExecutor.access$100(TableWithExecutor.java:14) 
    at TableWithExecutor$MyTask.doInBackground(TableWithExecutor.java:92) 
    at TableWithExecutor$MyTask.doInBackground(TableWithExecutor.java:80) 
    at javax.swing.SwingWorker$1.call(SwingWorker.java:277) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at javax.swing.SwingWorker.run(SwingWorker.java:316) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
    at java.lang.Thread.run(Thread.java:680) 
StartShedule: STARTED -> DONE 

Full mã:

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.text.DateFormat; 
import java.util.Date; 
import java.util.List; 
import java.util.concurrent.Executor; 
import java.util.concurrent.Executors; 
import javax.swing.*; 
import javax.swing.table.*; 

/** @see https://stackoverflow.com/questions/7054627 */ 
public class TableWithExecutor extends JFrame { 

    private static final int delay = 1000; 
    private static final DateFormat df = DateFormat.getTimeInstance(); 
    private String[] columnNames = {"Product", "Availability"}; 
    private Object[][] data = {columnNames, columnNames, columnNames}; 
    private DefaultTableModel model; 
    private JTable table; 
    private Executor executor = Executors.newCachedThreadPool(); 
    private Timer timer; 

    public TableWithExecutor() { 
     model = new DefaultTableModel(data, columnNames); 
     table = new JTable(model) { 

      @Override 
      public Class getColumnClass(int column) { 
       return getValueAt(0, column).getClass(); 
      } 
     }; 
     table.setDefaultRenderer(Date.class, new DefaultTableCellRenderer() { 

      @Override 
      protected void setValue(Object value) { 
       setText((value == null) ? "" : df.format(value)); 
      } 
     }); 
     table.setPreferredScrollableViewportSize(new Dimension(200, 100)); 
     JScrollPane scrollPane = new JScrollPane(table); 
     add(scrollPane, BorderLayout.CENTER); 
     timer = new Timer(delay, startCycle()); 
     timer.setRepeats(true); 
     timer.start(); 
    } 

    private Action startCycle() { 
     return new AbstractAction(MyTask.STARTSCHEDULE) { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       executor.execute(new MyTask(MyTask.STARTSCHEDULE)); 
      } 
     }; 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       TableWithExecutor frame = new TableWithExecutor(); 
       frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    private class MyTask extends SwingWorker<List<DateRecord>, DateRecord> { 

     private static final String STARTSCHEDULE = "StartSchedule"; 
     private String name = STARTSCHEDULE; 

     MyTask(String name) { 
      this.name = name; 
      addPropertyChangeListener(new TaskListener(name)); 
     } 

     @Override 
     protected List<DateRecord> doInBackground() throws Exception { 
      for (int row = 0; row < model.getRowCount(); row++) { 
       Date date = new Date(); 
       date.setTime(date.getTime() + row * 1000); 
       publish(new DateRecord(row, date)); 
      } 
      return null; 
     } 

     @Override 
     protected void process(List<DateRecord> chunks) { 
      for (DateRecord dr : chunks) { 
       model.setValueAt(dr.date, dr.rowNumber, 1); 
      } 
     } 

     @Override 
     protected void done() { 
      try { 
       get(); 
      } catch (Exception e) { 
       e.printStackTrace(System.err); 
      } 
     } 
    } 

    private static class DateRecord { 

     private int rowNumber; 
     private Date date; 

     public DateRecord(int recordNumber, Date date) { 
      this.rowNumber = recordNumber; 
      this.date = date; 
     } 
    } 

    private static class TaskListener implements PropertyChangeListener { 

     private String name; 

     TaskListener(String name) { 
      this.name = name; 
     } 

     @Override 
     public void propertyChange(PropertyChangeEvent e) { 
      System.out.println(name + ": " 
       + e.getOldValue() + " -> " + e.getNewValue()); 
     } 
    } 
} 
+0

(quan trọng nhất) và sau đó chỉ thay đổi 'bảo vệ Void doInBackground() ném ngoại lệ {...}' vào tiêu chuẩn 'try -> catch -> finally' block, sau đó là phép lạ, nhờ +1 – mKorbel

+0

@ Eng.Fouad : Tôi phải đề cập rằng ví dụ này được dự định để hiển thị lỗi. Lưu ý rằng nó (không chính xác) đã cập nhật GUI từ 'doInBackground()'. Tôi đã cập nhật mã cho phù hợp. – trashgod

+1

hmm .. bạn đang truy cập vào mô hình trên luồng nền, có đủ an toàn không? (Tự hỏi về điều đó trong câu hỏi gần đây của tôi :-) – kleopatra

10

Tôi nghĩ vấn đề bạn đang chạy vào đó là trường hợp ngoại lệ bị bắt trong thread nền chỉ được ném lại nếu bạn gọi get() khi quá trình xử lý hoàn tất. Điều này có vẻ là một vấn đề phổ biến với SwingWorker.

Bạn có thể thay đổi chức năng của bạn để done():

@Override 
protected void done() { 
    if (str.equals("StartShedule")) { 
     try { 
      get(); 
     } 
     catch (Exception ex) { 
      // This exception was thrown during processing 
      ex.printStackTrace(); 
     } 
    } 
} 

done() được thực hiện trên các chủ đề sự kiện văn để bạn có thể hiển thị bất kỳ thông báo lỗi bạn cần phải từ đó. Tôi hy vọng nó giúp đỡ một vài thứ.

+0

cảm ơn, rằng những gì/mà các phương pháp trở printStackTrace đầy đủ() Đúng vậy, nhưng, bởi vì bây giờ tôi chỉ thấy 'exception' Got nếu ngoại lệ (s) tồn tại – mKorbel

+0

hmmmm có lẽ tôi tìm kiếm trên những nơi sai lầm không có ý tưởng làm thế nào để có được printStackTrace đầy đủ(); btw +1 – mKorbel

+1

điều này hoàn toàn là điều bạn phải làm khi bạn sử dụng SwingWorker. Tôi nghĩ rằng các tài liệu nên hilight thực tế này tốt hơn. Một ngoại lệ được coi là kết quả "cuối cùng" của một chuỗi công nhân. Điều này có nghĩa là một SwingWorker không trả về bất kỳ đối tượng hoặc giá trị nào, tuy nhiên vẫn được kiểm tra kết quả bằng phương thức get(), sẽ làm cho trường hợp ngoại lệ phát sinh trong luồng công nhân. Hãy nhớ rằng các ngoại lệ đi lên ngăn xếp, nhưng trong một ứng dụng đa luồng có một ngăn xếp cho mỗi luồng. – AgostinoX