问题描述
我正在开发一个需要从给定的URL下载文件的任务,其中一个要求是可以处理网络故障和异常。
在我的实现中有一个DonwloadManager为每个URL分配一个线程,以免阻塞。
问题是我不知道如何通过代码模拟故障和异常,我尝试使用Quartz作为调度程序和一个仅抛出异常的作业,但据我所知,调度程序运行在不同的线程上,所以这不会影响下载线程。
有没有办法模拟下载线程中的例外?
以下是我的代码以获得更多见解:
public class DownloadManager {
intignedMemory = 0;
void validateURLs(String [] urls){
if(urls.length == 0){
throw new IllegalArgumentException(URL 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>();
allocateMemory = memorySize / urls.length;
(String url:urls){
completionService.submit(new DownloadWorker(url,assignedMemory));
}
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;
}
这是下载工作者:
class DownloadWorker实现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状态调用()throws异常{
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(); (int i = 0; i< buffer.limit(); i ++){
outputChannel.write(buffer);
}
buffer.clear();
}
outputChannel.close();
inputChannel.close();
outputFile.close();
return new Status(assignedURL,true);
}
}
关于如何以编程方式模拟/测试异常的任何建议?
更新:我在想,而不是排除异常,更容易模拟未来的状态,所以它将返回一个例外。
在您的 DownloadWorker
中, 6秒,当您在 DownloadManager
线程中获取 Future
时,设置 timeout
5秒。现在你将得到超时
异常。
这样,列出异常
你想抓住
DownloadManager
线程,并将它们从您的 DownloadWorker
中删除。
其他方式是按照以下方式执行执行方法之后的 ThredPoolExecutor
:
请注意,
FutureTask
会吞下异常(如果在上使用submit()而不是execute() ExecutorService
。查看源代码,因此从 DownloadWorker
正确地引发异常。 I'm developing a task that requires downloading files from given URLs, one of the requirement is that it could handle network failures and exceptions.
In my implementation I had a DonwloadManager that assigns a thread for every URL, so as not to be blocking.
The problem is that I am not sure how to mock failures and exceptions through the code, I tried using Quartz as scheduler and a job that only throws exception, but as far as I know the scheduler runs on different thread, so this won't affect the downloading thread at all.
Is there a way to mock the exceptions within the downloading thread ?
Here is my code for more insights:
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;
}
And this is the download 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);
}
}
Any suggestions on how to mock/test the exception programmatically ?
Update: I was thinking, instead of scheduling exceptions, it would be easier to mock the resulting Future status, so that it returns an exception.
In your DownloadWorker
, sleep for 6 seconds and when you are getting a Future
in DownloadManager
thread, set timeout
as 5 seconds. Now you will get timeout
exception.
In this way, list out Exceptions
you want to catch in DownloadManager
thread and throw them from your DownloadWorker
.
Other way is overriding ThredPoolExecutor
after execute method as per this one:
Handling exceptions from Java ExecutorService tasks
Note that FutureTask
s swallows the exceptions (if you use submit() instead of execute() on ExecutorService
. Have a look at source code. So raise exceptions properly from DownloadWorker
.
这篇关于在Java中安排例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!