Java并发性-任务反馈

从我 上一篇 关于java.util.concurrent包的 文章 的结尾处 摘下来 ,这很有趣,有时甚至必须在并发任务启动后从它们那里获得反馈。

例如,假设一个应用程序必须发送电子邮件批处理,除了使用多线程机制外,您还想知道成功发送了多少预期的电子邮件,以及在实际发送过程中,整个邮件的实时进度批量。

为了实现带有反馈的这种多线程,我们可以使用 Callable 接口。 该接口的工作方式与 Runnable 大致相同 ,但是执行方法(call())返回的值应反映所执行计算的结果。

让我们首先定义将执行实际任务的类:

package com.ricardozuasti;

import java.util.concurrent.Callable;

public class FictionalEmailSender implements Callable<Boolean> {
    public FictionalEmailSender (String to, String subject, String body){
        this.to = to;
        this.subject = subject;
        this.body = body;
    }

    @Override
    public Boolean call() throws InterruptedException {
        // Simulate that sending the email takes between 0 and 0.5 seconds
        Thread.sleep(Math.round(Math.random()* 0.5 * 1000));

        // Lets say we have an 80% chance of successfully sending our email
        if (Math.random()>0.2){
            return true;
        } else {
            return false;
        }
    }

    private String to;
    private String subject;
    private String body;
}

请注意, Callable可以使用任何返回类型,因此您的任务可以返回所需的任何信息。

现在,我们可以使用线程池ExecutorService发送电子邮件,并且由于我们的任务是作为Callable实现的,因此对于提交给执行的每个新任务,我们都会获得Future参考。 请注意,我们将使用直接构造函数而不是Executors中的实用程序方法来创建ExecutorService ,这是因为使用特定类( ThreadPoolExecutor )提供了一些方便的方法(在ExecutorService接口中不存在)。

package com.ricardozuasti;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Concurrency2 {

    public static void main(String[] args) {
        try {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(30, 30, 1, TimeUnit.SECONDS,
                    new LinkedBlockingQueue());

            List<Future<Boolean>> futures = new ArrayList<Future<Boolean>>(9000);

            // Lets spam every 4 digit numeric user on that silly domain
            for (int i = 1000; i < 10000; i++) {
                futures.add(executor.submit(new FictionalEmailSender(i + '@wesellnumericusers.com',
                        'Knock, knock, Neo', 'The Matrix has you...')));
            }

            // All tasks have been submitted, wen can begin the shutdown of our executor
            System.out.println('Starting shutdown...');
            executor.shutdown();

            // Every second we print our progress
            while (!executor.isTerminated()) {
                executor.awaitTermination(1, TimeUnit.SECONDS);
                int progress = Math.round((executor.getCompletedTaskCount() * 100) /
                                          executor.getTaskCount());

                System.out.println(progress + '% done (' + executor.getCompletedTaskCount() +
                                   ' emails have been sent).');
            }

            // Now that we are finished sending all the emails, we can review the futures
            // and see how many were successfully sent
            int errorCount = 0;
            int successCount = 0;
            for (Future<Boolean> future : futures) {
                if (future.get()) {
                    successCount++;
                } else {
                    errorCount++;
                }
            }

            System.out.println(successCount + ' emails were successfully sent, but '
                    + errorCount + ' failed.');

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

在将所有任务提交给ExecutorService之后 ,我们开始关闭它(防止提交新任务),并使用循环(在实际情况下,如果可能,您应该继续执行其他操作)等待所有任务完成,然后进行计算并打印到目前为止每次迭代的进度。 请注意,您可以随时存储执行程序引用并从其他线程查询它,以计算和报告流程进度。

最后,使用对每个提交给ExecutorService的 CallableFuture引用的集合,我们可以告知成功发送的电子邮件数量和失败的电子邮件数量。

这种基础结构不仅易于使用,而且还可以促进关注点的清晰分离,从而在调度程序和实际任务之间提供了预定义的通信机制。

参考: Java并发示例–Ricardo Zuasti的博客博客中,从我们的JCG合作伙伴 Ricardo Zuasti 获得并发任务的反馈


翻译自: https://www.javacodegeeks.com/2012/06/java-concurrency-feedback-from-tasks.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以回答这个问题。基于多线程的端口扫描程序可以使用 Java 编写。通过创建多个线程,每个线程负责扫描一定范围的端口,可以大大提高扫描速度。同时,需要注意线程安全问题,避免多个线程同时访问同一个资源导致的竞争问题。 ### 回答2: 基于多线程的端口扫描程序可以使用Java语言实现。下面是一个简单的实现示例: ```java import java.net.*; import java.util.concurrent.*; public class PortScanner { public static void main(String[] args) { String host = "localhost"; //要扫描的主机 int startPort = 1; //起始端口号 int endPort = 65535; //结束端口号 int timeout = 100; //超时时间(毫秒) int numThreads = 100; //线程数 ExecutorService executor = Executors.newFixedThreadPool(numThreads); for (int port = startPort; port <= endPort; port++) { executor.submit(new PortScanTask(host, port, timeout)); } executor.shutdown(); } private static class PortScanTask implements Runnable { private String host; private int port; private int timeout; public PortScanTask(String host, int port, int timeout) { this.host = host; this.port = port; this.timeout = timeout; } @Override public void run() { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress(host, port), timeout); System.out.println("端口 " + port + " 开放"); socket.close(); } catch (Exception ex) { //捕获异常说明端口关闭或无法连接 } } } } ``` 以上代码创建了一个ExecutorService线程池来管理线程。然后,使用for循环遍历指定范围内的端口号,并提交任务给线程池。每个任务通过Socket连接检查对应端口是否开放。如果连接成功,则说明端口开放,打印相关信息。如果连接失败,则说明端口关闭或无法连接。 在实际使用中,可以根据需求调整主机地址、起始和结束端口号、超时时间以及线程数等参数。此示例只是一个基本的多线程端口扫描程序,可以根据实际需求进行优化和扩展。 ### 回答3: 基于多线程的端口扫描程序是使用Java编写的一种网络安全工具。它通过同时运行多个线程来扫描一个或多个目标主机上的开放端口。以下是一个简单的实现示例: 首先,我们需要创建一个扫描器类,负责实现端口扫描的逻辑。该类需要继承Thread类,并重写run()方法,用于执行具体的扫描操作。在run()方法中,我们可以使用Socket类来建立与目标主机的连接,并检查特定端口是否开放。 接下来,我们需要创建一个扫描器管理类,用于创建和管理扫描器的线程。在该类中,我们可以定义一个线程池,用于存储所有扫描器线程的引用。线程池的大小可以根据需求进行调整。在执行扫描操作之前,我们需要通过调用线程池的execute()方法来启动线程。 在执行端口扫描之前,我们需要从用户那里获得目标主机的IP地址和要扫描的端口范围。可以使用Scanner类或命令行参数来实现这一点。 当线程启动后,每个线程将尝试连接目标主机的一个端口。如果连接成功,则说明该端口是开放的。程序可以通过输出结果或记录到文件中来显示或存储这些信息。 扫描完成后,我们需要关闭所有线程,并进行必要的清理操作。 由于端口扫描属于网络安全领域,使用这种多线程的扫描程序需要遵循合适的法律和道德规范。在实际使用中,还需要考虑并发访问控制、资源管理和错误处理等方面的问题。 在实际应用中,还可以对扫描程序进行进一步的改进,例如添加超时检测、扫描速度控制和结果过滤等功能,以提高能和可靠。 总结来说,基于多线程的端口扫描程序是一个利用Java多线程技术实现的网络安全工具,可以快速扫描目标主机上的开放端口,并提供实时结果反馈

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值