日期:2014-05-17  浏览次数:20587 次

文件上传中的一个致命异常
我通过struts1+apache的fileUpload实现文件上传功能,但是因为要考虑并发的问题,所以我加入了线程池对其进行管理,当把代码复制到run()方法中时,它提示要把request与response全部设成final类型,之后,问题就接踵而来了。在执行到:
List <FileItem> fileItems = upload.parseRequest(request);这一句时就报异常了,如下:
org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:294)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:116)
at com.dtcloud.action.UploadAction$1.run(UploadAction.java:81)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)

在网上找了半天都没找到想对应的回答,我们做的是移动开发,后台是通过手机端访问的。在没加线程池的时候访问是正常的,知道的朋友还望指点一二,谢谢啦!!!

------解决方案--------------------
所以,楼主啊,问题跟我说的是一致的。

你看你最后的两端代码:
threadPool.execute(new Runnable() {
...
});
return null;

当主线程利用threadPool启动了子线程去处理文件上传后,你的主线程其实就 return null; 了,那么中间件(Tomcat或JBOSS,不知道你用的是啥)就会把整个请求全部结束掉了,也就是request和response都会结束掉。那么你的子线程当然什么东西都干不了了。

你可以尝试在return null;这句话的前面增加
try {threadPool.awaitTermination(60, TimeUnit.SECONDS);} catch (Exception ex){}
看看问题是否迎刃而解?
但其实这就已经丧失了你最开始的设计初衷了。


但,总的来说,楼主,我认为你过度设计了。
中间件的整个设计本身已经有线程池的概念,并且也已经很好的支持了并发需求,你是不能企图用自己的线程池去接管它的工作的。原则上来说,J2EE开发,是不建议有类似创建子线程的代码的。

我认为你没有任何合理的理由去这么做。
如果你认为你有,那么请说出来,我们探讨下是否有更合理的模式,而不是采用这种方式。