2011-05-24 9 views
6

Hiện tại tôi có hai chuỗi SwingWorker đang thực hiện công việc trên nền. Nếu một ngoại lệ xảy ra, phương thức dừng hoạt động, nhưng luồng vẫn chạy.Làm thế nào hủy bỏ việc thực hiện một SwingWorker?

Tôi làm cách nào để ngừng thực hiện và giết chủ đề của doInBackground() nếu có ngoại lệ?

this.cancel(true) không hủy/đóng chuỗi. Làm thế nào tôi có thể đạt được điều này?

@Override 
protected Boolean doInBackground() throws Exception { 
     try { 
      while (true) { 
       //some code here     
       return true; 
      } 
     } catch (Exception e) {  
      this.cancel(true); //<-- this not cancel the thread    
      return false; 
     } 
    } 

Tôi thấy các chủ đề này trong gỡ lỗi của Netbeans.

'AWT-EventQueue-0' em execução 
'AWT-Windows' em execução 
'SwingWorker-pool-1-thread-1' em execução 
'SwingWorker-pool-1-thread-2' em execução 

//*em execução = in execution 
+0

Bạn có thể xác nhận rằng 'doInBackground()' trả về và không chặn bên trong vòng lặp 'while (true)'? – jfpoilpret

+0

Có, tôi đã sửa mã và nó nhập vào ngoại lệ trả về sai. –

Trả lời

7

Theo mặc định, SwingWorker reuses đề người lao động, vì vậy nó là hoàn toàn bình thường mà, mặc dù, doInBackground() đã trở lại, vẫn thấy các chủ đề mà thực hiện phương pháp của bạn.

Bạn có thể xác định thực tế này bằng cách nhìn vào tên chủ đề, theo báo cáo của NetBeans: SwingWorker-pool-1-thread-1, nơi mà hồ bơi được quản lý bởi SwingWorker.

Nếu bạn muốn kiểm soát nhiều hơn, bạn cũng có thể chuyển thể hiện SwingWorker đến Executor.

Chỉ cần kiểm tra SwingWorkerExecutor javadoc để biết thêm thông tin.

Bên cạnh đó, SwingWorker.cancel() không được gọi là từ doInBackground() mà là từ một chủ đề khác, thường là EDT, ví dụ: khi người dùng nhấp vào nút Hủy trong hộp thoại tiến trình.

+0

Nó không tái sử dụng, mỗi lần tôi bấm vào nút để quá trình sẽ chạy trong nền nó tạo ra một chủ đề mới. Tôi sẽ thử gọi từ một chủ đề khác để xem điều gì xảy ra. –

+0

Khó để nói, nhưng bạn không thể nắm vững cách 'SwingWorker' giao dịch với các nhóm luồng và gán một cá thể' SwingWorker' đã cho cho một luồng trong hồ bơi. Như tôi đã nói, nếu bạn muốn toàn quyền kiểm soát, thì bạn có thể sử dụng một trong các hiện thực hiện có của 'Executor', hoặc xây dựng của riêng bạn, và truyền các cá thể' SwingWorker' của bạn tới phương thức 'execute' của nó. – jfpoilpret

+0

đã đồng ý, nhưng Executor cộng với SwingWorker 1) vẫn nằm trong top25 http://bugs.sun.com/top25_bugs.do 2) nếu bạn muốn thực sự Đa luồng, thì bạn phải Đặt tên cho chủ đề của bạn 3) thêm PropertyChangeListener cho SwingWorker, sau đó bạn có thể biết trạng thái của SwingWorker 4) là caffefull với số lượng Threads đồng thời bắt đầu từ Executor, bởi vì Executor không biết nếu SwingWorker kết thúc hay không 5) để tránh bất kỳ sự thất bại nào từ giá trị boolean boolean, thì chỉ kiểm tra giá trị từ PropertyChangeListener line from done(), trả về true một xác nhận rằng thread kết thúc mà không có bất kỳ fauls nào – mKorbel

4

Có phương thức cancel(). Mã của bạn sẽ phải chú ý đến điều đó. Nếu nó tiếp tục chạy sau khi một ngoại lệ, nó sẽ xuất hiện rằng bạn mã là bỏ qua một ngoại lệ mà nó không nên.

+0

Vâng, tôi thấy một cái gì đó như thế này, nhưng những phương pháp này được gọi là bên trong ngoại lệ với một this.cancel (true); hoặc trong lớp gọi phương thức thực hiện của SwingWorker? –

+1

Phương thức hủy có nghĩa là đối với các đối tượng thực hiện cuộc gọi. Nếu SwingWorker cần dừng thực thi vì ngoại lệ, thì Ngoại lệ đó cần phải được xử lý chính xác. – jzd

9

như jzd được tạo hình, có phương pháp cancel(boolean mayInterruptIfRunning); cho exapmle

CHỈNH SỬA: với hủy (đúng); bạn phải (luôn luôn) cautgh một ngoại lệ java.util.concurrent.CancellationException

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.util.ArrayList; 

public class SwingWorkerExample extends JFrame implements ActionListener { 

    private static final long serialVersionUID = 1L; 
    private final JButton startButton, stopButton; 
    private JScrollPane scrollPane = new JScrollPane(); 
    private JList listBox = null; 
    private DefaultListModel listModel = new DefaultListModel(); 
    private final JProgressBar progressBar; 
    private mySwingWorker swingWorker; 

    public SwingWorkerExample() { 
     super("SwingWorkerExample"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     getContentPane().setLayout(new GridLayout(2, 2)); 
     startButton = makeButton("Start"); 
     stopButton = makeButton("Stop"); 
     stopButton.setEnabled(false); 
     progressBar = makeProgressBar(0, 99); 
     listBox = new JList(listModel); 
     scrollPane.setViewportView(listBox); 
     getContentPane().add(scrollPane); 
     //Display the window. 
     pack(); 
     setVisible(true); 
    } 
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground 
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's 
//publish and process methods 

    private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> { 
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(), 
//and by get(). The second template argument, in this case, Integer, is what is published with the 
//publish method. It is also the data type which is stored by the java.util.List that is the parameter 
//for the process method, which recieves the information published by the publish method. 

     @Override 
     protected ArrayList<Integer> doInBackground() { 
//Returns items of the type given as the first template argument to the SwingWorker class. 
      if (javax.swing.SwingUtilities.isEventDispatchThread()) { 
       System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true."); 
      } 
      Integer tmpValue = new Integer(1); 
      ArrayList<Integer> list = new ArrayList<Integer>(); 
      for (int i = 0; i < 100; i++) { 
       for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower 
        tmpValue = FindNextPrime(tmpValue.intValue()); 
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way 
//to stop this thread. See the actionPerformed method. 
        if (isCancelled()) { 
         System.out.println("SwingWorker - isCancelled"); 
         return list; 
        } 
       } 
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process, 
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from 
//1 to 100. 
       publish(new Integer(i)); 
       list.add(tmpValue); 
      } 
      return list; 
     }//Note, always use java.util.List here, or it will use the wrong list. 

     @Override 
     protected void process(java.util.List<Integer> progressList) { 
//This method is processing a java.util.List of items given as successive arguments to the publish method. 
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the 
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the 
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar. 
      if (!javax.swing.SwingUtilities.isEventDispatchThread()) { 
       System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false."); 
      } 
      Integer percentComplete = progressList.get(progressList.size() - 1); 
      progressBar.setValue(percentComplete.intValue()); 
     } 

     @Override 
     protected void done() { 
      System.out.println("doInBackground is complete"); 
      if (!javax.swing.SwingUtilities.isEventDispatchThread()) { 
       System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false."); 
      } 
      try { 
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter 
//given to the SwingWorker class. 
       ArrayList<Integer> results = get(); 
       for (Integer i : results) { 
        listModel.addElement(i.toString()); 
       } 
      } catch (Exception e) { 
       System.out.println("Caught an exception: " + e); 
      } 
      startButton(); 
     } 

     boolean IsPrime(int num) { //Checks whether a number is prime 
      int i; 
      for (i = 2; i <= num/2; i++) { 
       if (num % i == 0) { 
        return false; 
       } 
      } 
      return true; 
     } 

     protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.  
      do { 
       if (num % 2 == 0) { 
        num++; 
       } else { 
        num += 2; 
       } 
      } while (!IsPrime(num)); 
      return new Integer(num); 
     } 
    } 

    private JButton makeButton(String caption) { 
     JButton b = new JButton(caption); 
     b.setActionCommand(caption); 
     b.addActionListener(this); 
     getContentPane().add(b); 
     return b; 
    } 

    private JProgressBar makeProgressBar(int min, int max) { 
     JProgressBar progressBar1 = new JProgressBar(); 
     progressBar1.setMinimum(min); 
     progressBar1.setMaximum(max); 
     progressBar1.setStringPainted(true); 
     progressBar1.setBorderPainted(true); 
     getContentPane().add(progressBar1); 
     return progressBar1; 
    } 

    private void startButton() { 
     startButton.setEnabled(true); 
     stopButton.setEnabled(false); 
     System.out.println("SwingWorker - Done"); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) { 
      startButton.setEnabled(false); 
      stopButton.setEnabled(true); 
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one. 
      (swingWorker = new mySwingWorker()).execute(); // new instance 
     } else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) { 
      startButton.setEnabled(true); 
      stopButton.setEnabled(false); 
      swingWorker.cancel(true); // causes isCancelled to return true in doInBackground 
      swingWorker = null; 
     } 
    } 

    public static void main(String[] args) { 
// Notice that it kicks it off on the event-dispatching thread, not the main thread. 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       SwingWorkerExample swingWorkerExample = new SwingWorkerExample(); 
      } 
     }); 
    } 
} 
+0

Phương thức isCancelled() trả về true sau phương thức cancel(), nhưng tại sao luồng 'SwingWorker-pool-1-thread-1' vẫn xuất hiện như trong thực thi? –

+0

'SwingWorker-pool-1-thread-2' cũng xuất hiện. –

+0

giải thích tốt như tất cả được đưa ra ở đây (+1 tất cả). Ví dụ này là khổng lồ nhưng tôi thích nó nhờ :) – Boro

2

Bạn cần phải thêm Thread.sleep(1) cuộc gọi trong doInBackground() mã của bạn tất cả vì vậy thường xuyên. Trong giấc ngủ của bạn bắt khối, thêm return. Tôi đã có cùng một vấn đề, và điều này làm việc như một say mê.

Nguồn: https://blogs.oracle.com/swinger/entry/swingworker_stop_that_train

+1

Cảm ơn bạn đã chia sẻ, điều này rất hữu ích! – DSquare

0

Till The SwingWoker nó cố định http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514 Dưới đây là một đơn giản (thử nghiệm) phiên bản với cơ bản (tương tự) các chức năng sau đó SwingWoker

/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package tools; 

import java.util.LinkedList; 
import java.util.List; 
import javax.swing.SwingUtilities; 

/** 
* 
* @author patrick 
*/ 
public abstract class MySwingWorker<R,P> { 

    protected abstract R doInBackground() throws Exception; 
    protected abstract void done(R rvalue, Exception ex, boolean canceled); 
    protected void process(List<P> chunks){} 
    protected void progress(int progress){} 

    private boolean cancelled=false; 
    private boolean done=false; 
    private boolean started=false; 
    final private Object syncprogress=new Object(); 
    boolean progressstate=false; 
    private int progress=0; 
    final private Object syncprocess=new Object(); 
    boolean processstate=false; 
    private LinkedList<P> chunkes= new LinkedList<>(); 

    private Thread t= new Thread(new Runnable() { 
     @Override 
     public void run() { 
      Exception exception=null; 
      R rvalue=null; 
      try { 
       rvalue=doInBackground(); 
      } catch (Exception ex) { 
       exception=ex; 
      } 

      //Done: 
      synchronized(MySwingWorker.this) 
      { 
       done=true; 
       final Exception cexception=exception; 
       final R crvalue=rvalue; 
       final boolean ccancelled=cancelled; 

       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         done(crvalue, cexception, ccancelled); 
        } 
       }); 
      } 

     } 
    });  

    protected final void publish(P p) 
    { 
     if(!Thread.currentThread().equals(t)) 
      throw new UnsupportedOperationException("Must be called from worker Thread!"); 
     synchronized(syncprocess) 
     { 
      chunkes.add(p); 
      if(!processstate) 
      { 
       processstate=true; 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         List<P> list; 
         synchronized(syncprocess) 
         { 
          MySwingWorker.this.processstate=false; 
          list=MySwingWorker.this.chunkes; 
          MySwingWorker.this.chunkes= new LinkedList<>(); 
         } 
         process(list); 
        } 
       }); 
      } 
     } 
    } 

    protected final void setProgress(int progress) 
    { 
     if(!Thread.currentThread().equals(t)) 
      throw new UnsupportedOperationException("Must be called from worker Thread!"); 
     synchronized(syncprogress) 
     { 
      this.progress=progress; 
      if(!progressstate) 
      { 
       progressstate=true; 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         int value; 
         //Acess Value 
         synchronized(syncprogress) 
         { 
          MySwingWorker.this.progressstate=false; 
          value=MySwingWorker.this.progress; 
         } 
         progress(value); 
        } 
       }); 
      } 
     } 
    } 

    public final synchronized void execute() 
    { 
     if(!started) 
     { 
      started=true; 
      t.start(); 
     } 
    } 

    public final synchronized boolean isRunning() 
    { 
     return started && !done; 
    } 

    public final synchronized boolean isDone() 
    { 
     return done; 
    } 

    public final synchronized boolean isCancelled() 
    { 
     return cancelled; 
    } 

    public final synchronized void cancel() 
    { 
     if(started && !cancelled && !done) 
     { 
      cancelled=true; 
      if(!Thread.currentThread().equals(t)) 
       t.interrupt(); 
     } 
    } 

}