qq_38291548
2020-04-20 17:09
采纳率: 50%
浏览 148
已采纳

并行访问接口流被关闭

res: (respnse) => {
              console.info(respnse.result.active)
              let url = respnse.result.active == 'dev'
                ?'http://10.68.105.145:8081/sxhblh-boot/trainmanage/trainInfo/visitImg?imgName=' + respnse.result.url
                :'http://ctg.com.cn:8081/sxhblh-boot/trainmanage/trainInfo/visitImg?imgName=' + respnse.result.url
              return url
            },
    @GetMapping("visitImg")
@ResponseBody
public synchronized void visitImg(String imgName,HttpServletResponse response){
    String path;
    InputStream inputStream = null;
    BufferedInputStream bufferedInputStream = null;
    BufferedOutputStream bufferedOutputStream = null;
    try {
        path = "img";
        inputStream = FtpClientUtil.readFile(imgName,path);
        bufferedInputStream = new BufferedInputStream(inputStream);

        bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
        byte[] buf = new byte[1024 * 1024];
        int length = 0;
        while ((length = bufferedInputStream.read(buf)) != -1) {
            bufferedOutputStream.write(buf, 0, length);
            bufferedOutputStream.flush();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inputStream.close();
            bufferedInputStream.close();
            bufferedOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

如第一段代码所示,这是上传图片后的回调,给图片设置src,可以看到,所有的图片访问调用的都是同一个接口visitImg,参数为imgName,现在的问题是,上传多个图片后,始终只能显示第一个图片,后面的图片都无法显示,后台报错stream closed流关闭,但是我打了断点之后,会进多次断点,并且图片都能显示,然后我在想是不是打了断点之后,上一次请求阻塞下一次请求,使得本来所有图片的访问从并行变为了串行,由此思考我想到了一个解决办法,给方法加上锁synchronized,问题解决了。问题是解决了,但是问题的本质我还是没有弄懂,1、为什么并行访问接口会导致stream closed流被关闭,2、还有没有更好的解决办法(一开始还想在前端设置请求队列,但是请求是以src的形式,所以放弃了),还请各位大神们赐教

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • 毕小宝 2020-04-21 09:20
    已采纳

    需要加上 synchronized ,是因为 Controller 类是单例,所有浏览器访问这个请求方法时,都会调用这个类的实例的。
    但 Tomcat 是开启多个线程处理浏览器请求的,所以这个类是多线程环境下,需要安全同步措施。
    如果恰好文件名称相同 FtpClientUtil 这个获取文件方法可能也存在多线程同步问题,目标对象为同一个文件的时候,可能会出现 StreamClose 这个要看异常才知道是什么流关闭。

    加上断点后后面请求被迫暂停,所以本质是是顺序的。Web 请求一般都是后台做并发控制的,synchronize 加在整个方法上,优化的话可以缩小加锁粒度,只在文件处理那段代码上加锁。

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • threenewbee 2020-04-20 18:08

    FtpClientUtil.这个类你自己写的?有没有同步,是否是线程安全的。
    检查代码里是不是两个线程访问同一个流了。

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题