簡體   English   中英

如何從Swing Worker運行服務執行程序?

[英]How to run service executor from Swing worker?

我正在編寫IP掃描儀應用程序,該過程耗時很長,因此我在gui的后台使用的是服務執行程序,例如:

 public static List<Future<String>> checkThisIP(String ipStart, String ipEnd) throws UnknownHostException {
    final ExecutorService es = Executors.newFixedThreadPool(10);
    final List<Future<String>> futures = new ArrayList<>();
    String ipStringStart;
    String ipStringEnd;
    String targetIpString;
    //my update
    ipStringStart = ipStart.substring(ipStart.lastIndexOf(".") + 1, ipStart.length());
    ipStringEnd = ipEnd.substring(ipEnd.lastIndexOf(".") + 1, ipEnd.length());
    targetIpString = ipStart.substring(0, ipStart.lastIndexOf(".") + 1);
    if (!ipStart.equals(ipEnd)) {
        for (int i = Integer.parseInt(ipStringStart); i <= Integer.parseInt(ipStringEnd); i++) {
            String currentIp = targetIpString + i;
            futures.add(runPingScan(es, currentIp));
        }
    } else {
        futures.add(runPingScan(es, ipStart));
    }
    es.shutdown();
    return futures;
}


public static Future<String> runPingScan(final ExecutorService es, final String ip) {
    return es.submit(new Callable<String>() {
        @Override
        public String call() {
            String returnMe = "";
           //custom ping class 
            Ping p = new Ping();
            //send message
            p.SendReply(ip);
            //IsReachable returns ture or false
            if(p.IsReachable()){
                returnMe=ip;
            }
            return returnMe;
           }

    });
}

這是使用Jbutton執行的原始松散代碼操作:

 // scan result is Future list returned from service executor 
    List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
                    for (final Future<String> f : scanResult) {
                        try {
                            ip = f.get();
                            if (!ip.equals("")) {
                                arp ARP = new arp();
                                PortScan openPort = new PortScan();
                                IP ipClass = new IP();
                                mac = ARP.getMac(ip);
                                manufacturer = ARP.getOUI(mac);
                                ports = openPort.checkIpForPorts(ip);
                                hostname = ipClass.hostname(ip);
                                title = ipClass.htmlTitle(ip);
                                Object[] data = {ip, mac, manufacturer, ports, hostname, title};
                                tableModel.addRow(data);
                            }

                            if (jFormattedTextField1.getText().equals(jFormattedTextField2.getText()) && ip.equals("")) {
                                JOptionPane.showMessageDialog(null, "<html>Can not ping the address ! <br> Server might be protected by <b>WAF</b>.</html>", "Alert", HEIGHT);
                            }
                        } catch (Exception ex) {
                            Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

運行此代碼很好,但是當我將其附加到“ 開始掃描按鈕”時 ,GUI滯后了,我在Google上搜索並確定要使用Swing Worker 當我單獨使用搖擺工人時,它殺死了並發性,而當我同時使用這兩個GUI時,仍然落后。 我的問題是無論如何要使按鈕(Swing worker)調用服務執行程序來執行其他過程?

當我單獨使用搖擺工人時,它殺死了並發性,而當我同時使用這兩個GUI時,仍然落后。

這里有兩件事要做:

  • 將ping檢查分散在多個線程上

    • 將您的任務分為獨立的子任務
    • 在線程池中運行子任務
    • 收集結果
  • 將整個操作與事件分發線程分離

    • 注冊用戶操作(單擊,按鍵),從文本字段獲取數據,構建任務
    • 在EDT之外運行任務
    • 更新gui,顯示結果

您正在使用ExecutorService第一部分的代碼。 第二部分未在您的代碼中完成,因此EDT將阻塞,直到整個操作完成為止,這將導致GUI滯后。

您需要將以下代碼移至swing worker,后者在執行程序中運行任務:

List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
                for (final Future<String> f : scanResult) {
                    try {
                        [...] // this is where the thread blocks, making your ui lag if it's the EDT
                        Object[] data = {ip, mac, manufacturer, ports, hostname, title};

首先,移動所有將由執行者的線程池處理的阻塞代碼:

public static Future<Object[]> runPingScan(final ExecutorService es, final String ip) {
    return es.submit(new Callable<Object[]>() {
        @Override
        public Object[] call() {
            //custom ping class 
            Ping p = new Ping();
            //send message
            p.SendReply(ip);
            //IsReachable returns ture or false
            if(p.IsReachable()){
                [...] // other blocking code
                return {ip, mac, manufacturer, ports, hostname, title};
            } else {
                // special case, use null values or throw an exception
            }
        }
    });
}

然后,您可以使用“ 簡單背景任務”教程代碼將整個內容與EDT分離:

SwingWorker worker = new SwingWorker<List<Object[]>, Void>() {
    public List<Object[]> doInBackground() {
        // -- this will run in another thread --
        // submit ping checks to the executor
        List<Future<Object[]>> scanResult = [...]
        // get results, put them in a list, return it
        List<Object[]> result = new ArrayList<>();
        for(Future<Object[]> f : scanResult) {
            result.add(f.get()); // blocking happens here, outside of the EDT
        }
        return result;
    }

    public void done() {
        // -- this will run in the EDT --
        // get() the list created above
        // display the result in the gui
        for(Object[] data : get()) {
            tableModel.addRow(data);
        }
    }
};

這里不包括一些特殊情況,例如ping檢查失敗,您需要以某種方式處理它們。 調用f.get()包裝在ExecutionException時,將從可調用對象中引發的每個異常重新拋出。 在那些特殊情況下使用它可能是您的最佳選擇。

我已經設法通過實現swing worker解決了我的問題,后台執行的功能將為服務執行程序啟動新線程並防止延遲。

//The actionpreformed by the button
   SwingWorker worker = new SwingWorker<Void, Void>() {
            @Override
        // All actions are done this method
            protected Void doInBackground() throws Exception {
                String ip = "";
                String mac = "";
                String manufacturer = "";
                String ports = "";
                String hostname = "";
                String title = "";
                tableModel.setRowCount(0);
                PingScan p = new PingScan();
                List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
                for (final Future<String> f : scanResult) {
                    try {
                        ip = f.get();
                        if (!ip.equals("")) {
                            arp ARP = new arp();
                            PortScan openPort = new PortScan();
                            IP ipClass = new IP();
                            mac = ARP.getMac(ip);
                            manufacturer = ARP.getOUI(mac);
                            ports = openPort.checkIpForPorts(ip);
                            hostname = ipClass.hostname(ip);
                            title = ipClass.htmlTitle(ip);
                            Object[] data = {ip, mac, manufacturer, ports, hostname, title};
                            tableModel.addRow(data);
                        }
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                }
                return null;
            }
        };
     worker.execute();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM