Java 如何从Swing worker运行服务执行器?

Java 如何从Swing worker运行服务执行器?,java,swing,concurrency,swingworker,Java,Swing,Concurrency,Swingworker,我正在编写一个IP扫描器应用程序,该过程需要很长时间,因此我在gui的后台使用的是服务执行器,如: public static List<Future<String>> checkThisIP(String ipStart, String ipEnd) throws UnknownHostException { final ExecutorService es = Executors.newFixedThreadPool(10); final List&

我正在编写一个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;
           }

    });
}
publicstaticlist checkThisIP(stringipstart,stringipend)抛出UnknownHostException{
final Executors服务es=Executors.newFixedThreadPool(10);
最终列表期货=新的ArrayList();
字符串ipStringStart;
字符串ipstringed;
字符串目标字符串;
//我的更新
ipStringStart=ipStart.substring(ipStart.lastIndexOf(“.”+1,ipStart.length());
ipStringEnd=ipEnd.substring(ipEnd.lastIndexOf(“.”+1,ipEnd.length());
targetIpString=ipStart.substring(0,ipStart.lastIndexOf(“.”+1);
如果(!ipStart.equals(ipEnd)){
for(inti=Integer.parseInt(ipStringStart);i
当我单独实现swing worker时,它扼杀了并发性,而当我实现这两个gui时,仍然滞后

这里有两件事要做:

  • 将ping检查分散到多个线程上

    • 将任务拆分为独立的子任务
    • 在线程池中运行子任务
    • 收集结果
  • 从事件dispach线程分离整个操作

    • 注册用户操作(单击、按键)、从文本字段获取数据、生成任务
    • 在EDT之外运行任务
    • 更新gui,显示结果
您正在使用
ExecutorService
为部分代码执行第一部分。第二部分未在代码中完成,因此EDT将阻塞,直到整个操作完成,从而导致gui延迟

您需要将此代码移动到swing worker,后者在executor中运行任务:

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};
List scanResult=p.checkThisIP(jFormattedTextField1.getText(),jFormattedTextField2.getText());
对于(最终未来f:scanResult){
试一试{
[…]//这是线程阻塞的地方,如果是EDT,则会导致ui延迟
对象[]数据={ip、mac、制造商、端口、主机名、标题};
首先,移动所有要由执行器的线程池处理的阻塞代码:

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
            }
        }
    });
}
公共静态未来运行扫描(最终执行者服务,最终字符串ip){
返回es.submit(新的可调用(){
@凌驾
公共对象[]调用(){
//自定义ping类
Ping p=新Ping();
//发送消息
p、 发送回复(ip);
//IsReachable返回true或false
if(p.IsReachable()){
[…]//其他阻止代码
返回{ip、mac、制造商、端口、主机名、标题};
}否则{
//特殊情况下,使用空值或引发异常
}
}
});
}
然后,您可以使用教程代码从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);
        }
    }
};
SwingWorker-worker=新的SwingWorker(){
公共列表doInBackground(){
//--这将在另一个线程中运行--
//向执行人提交ping支票
列表扫描结果=[…]
//获取结果,将其放入列表中,然后返回
列表结果=新建ArrayList();
对于(未来f:scanResult){
result.add(f.get());//阻塞发生在这里,EDT之外
}
返回结果;
}
公众假期结束(){
//--这将在EDT中运行--
//获取()上面创建的列表
//在gui中显示结果
对于(对象[]数据:get()){
tableModel.addRow(数据);
}
}
};
这里没有包括的是一些特殊情况,例如ping检查失败,您需要以某种方式处理它们。在调用
f.get()
时,从您的可调用项中引发的每个异常都会在
ExecutionException
中重新抛出。对于这些特殊情况,使用它可能是您最好的选择

当我单独实现swing worker时,它扼杀了并发性,而当我实现这两个gui时,仍然滞后

这里有两件事要做:

  • 将ping检查分散到多个线程上

    • 将任务拆分为独立的子任务
    • 在线程池中运行子任务
    • 收集结果
  • 从事件dispach线程分离整个操作

    • 注册用户操作(单击、按键)、从文本字段获取数据、生成任务
    • 在EDT之外运行任务
    • 更新gui,显示结果
您正在使用
ExecutorService
为部分代码执行第一部分。第二部分未在代码中完成,因此EDT将阻塞,直到整个操作完成,从而导致gui延迟

您需要将此代码移动到swing worker,后者在executor中运行任务:

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};
List scanResult=p.checkThisIP(jFormattedTextField1.getText(),jFormattedTextField2.getText());
对于(最终未来f:scanResult){
试一试{
[…]//这是线程阻塞的地方,如果是EDT,则会导致ui延迟
对象[]数据={ip、mac、制造商、端口、主机名、标题};
首先,移动所有要由执行器的线程池处理的阻塞代码:

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
            }
        }
    });
}
公共静态未来运行扫描(最终执行者服务,最终字符串ip){
返回es.submit(新的可调用(){
@凌驾
公共对象[]调用(){
//自定义ping类
Ping p=新Ping();
//发送消息
p、 发送回复(ip);
//IsReachable返回true或false
if(p.IsReachable()){
[…]//其他阻止代码
返回{ip、mac、制造商、端口、主机名、标题};
}否则{
//特殊情况下,使用空值或引发异常
}
}
});
}
T