在 Java 中安排例外

Schedule exceptions in Java

我正在开发一项需要从给定的 URL 下载文件的任务,其中一个要求是它可以处理网络故障和异常。

在我的实现中,我有一个 DonwloadManager,它为每个 URL 分配一个线程,以免阻塞。

问题是我不确定如何通过代码模拟失败和异常,我尝试使用 Quartz 作为调度程序和一个只抛出异常的作业,但据我所知调度程序在不同的线程上运行,所以这根本不会影响下载线程。

有没有办法模拟下载线程中的异常?

这是我的代码以获得更多见解:

public class DownloadManager {

int allocatedMemory = 0;

void validateURLs(String[] urls) {
    if (urls.length == 0) {
        throw new IllegalArgumentException("URLs List is empty");
    }
}

public ArrayList<Status> downloadURLs(String[] urls, int memorySize) throws Exception {
    validateURLs(urls);
    ExecutorService executor = Executors.newWorkStealingPool();
    CompletionService<Status> completionService = new ExecutorCompletionService<Status>(executor);
    ArrayList<Status> downloadStatus = new ArrayList<Status>();
    allocatedMemory = memorySize / urls.length;
    for (String url : urls) {
       completionService.submit(new DownloadWorker(url, allocatedMemory));
    }
    for(int i=0;i<urls.length;i++){
       Future<Status> URLStatus =  completionService.take();
        System.out.println(URLStatus.get());
        downloadStatus.add(URLStatus.get());
    }
    executor.shutdown();
    return downloadStatus;
}

这是下载 Worker:

class DownloadWorker implements Callable<Status> {

static final int SUCCESS = 1, FAILURE = 0;

private int bufferSize;

private String assignedURL;

public DownloadWorker(String assignedURL, int bufferSize) {
    this.bufferSize = bufferSize;
    this.assignedURL = assignedURL;
}

public Status call() throws Exception {
    URLConnection openConnection = new URL(assignedURL).openConnection();
    openConnection.addRequestProperty("User-Agent",
            "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/39.0");
    String outputFileName = assignedURL.substring(assignedURL.lastIndexOf("/") + 1);
    RandomAccessFile outputFile = new RandomAccessFile(outputFileName, "rw");
    ReadableByteChannel inputChannel = Channels.newChannel(openConnection.getInputStream());
    FileChannel outputChannel = outputFile.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
    while (inputChannel.read(buffer) > 0) {
        buffer.flip();
        for (int i = 0; i < buffer.limit(); i++) {
            outputChannel.write(buffer);
        }
        buffer.clear();
    }
    outputChannel.close();
    inputChannel.close();
    outputFile.close();
    return new Status(assignedURL, true);
}

}

关于如何以编程方式 mock/test 异常的任何建议?

更新:我在想,与其安排异常,不如模拟结果 Future 状态更容易,这样它 returns 就会成为异常。

java executors 是另一种选择(参见 ExecutorService

  • 您可以在执行器中使用awaitTermination方法在当前线程中等待所有任务完成
  • 检查 Future(提交时返回的元素)是否存在异常

在您的 DownloadWorker 中休眠 6 秒,当您在 DownloadManager 线程中获得 Future 时,将 timeout 设置为 5 秒。现在你会得到 timeout 异常。

这样,列出Exceptions你想在DownloadManager线程中捕获并从你的DownloadWorker中抛出它们。

另一种方法是在执行方法之后覆盖 ThredPoolExecutor

Handling exceptions from Java ExecutorService tasks

请注意,FutureTasks 吞下了异常(如果您在 ExecutorService 上使用 submit() 而不是 execute())。查看源代码 code。因此正确地引发异常来自 DownloadWorker.