Semaphore处理高并发的内存溢出

         在项目实际应用中,由于下载文件内容都比较大,如果同时有很多用户同时在下载,JVM的内存就会升的很高,甚至崩溃。为了避免很多用户同时下载,特引入Semaphore控制一次最多有配置个线程能进入实际下载的代码,即而控制JVM内存不会升的很高而导致崩溃。

    import java.io.FileInputStream;  
    import java.io.IOException;  
    import java.io.InputStream;  
    import java.io.UnsupportedEncodingException;  
    import java.net.URLEncoder;  
    import java.util.List;  
    import java.util.Map;  
    import java.util.concurrent.Callable;  
    import java.util.concurrent.ExecutionException;  
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
    import java.util.concurrent.Future;  
    import java.util.concurrent.Semaphore;  
      
    import javax.servlet.ServletOutputStream;  
    import javax.servlet.http.HttpServletRequest;  
    import javax.servlet.http.HttpServletResponse;  
      
    import org.apache.commons.io.IOUtils;  
    import org.springframework.beans.factory.InitializingBean;  
    import org.springframework.stereotype.Component;  
      
    @Component("DownloadView.csv")  
    public class DownloadView extends AbstractCsvView implements InitializingBean {  
        //允许的最大线程数  
        private String threadNum=PropertyUtil.getProperty("threadNum");  
        // 线程池  
        private ExecutorService exec = null;  
        // 只能threadNum个线程同时访问  
        private Semaphore semp = new Semaphore(Integer.parseInt(threadNum), true);  
          
        @Override  
        protected void buildExcelDocument(Map<String, Object> model, List<String> csvList, HttpServletRequest request,  
                HttpServletResponse response) throws Exception  {  
            String fileName ="";  
            String url = request.getParameter("outputInfo");  
            if(StringUtil.isNotEmpty(url)){  
                fileName= url.substring(url.lastIndexOf("/") + 1, url.length());  
            }  
            super.setUrl(url);  
            try {  
                response.setHeader("Content-Disposition",  
                        "attachment;filename=" + URLEncoder.encode(fileName, response.getCharacterEncoding()));  
            } catch (UnsupportedEncodingException e) {  
                throw new Exception("不支持此编码格式");  
            }  
        }  
          
        @SuppressWarnings("unchecked")  
        @Override  
        protected void renderMergedOutputModel(final Map<String, Object> model, HttpServletRequest request,  
                HttpServletResponse response) throws Exception, IOException, InterruptedException, ExecutionException  {  
              
            exec = Executors.newCachedThreadPool();  
            response.setContentType(getContentType());  
            final String url = request.getParameter("outputInfo");  
            final ServletOutputStream out=response.getOutputStream();  
            final HttpServletRequest _request = request;  
            final HttpServletResponse _response = response;  
            InputStream in=null;  
            try{  
                in= new FileInputStream(url);  
            }catch(Exception e){  
                throw new Exception("找不到对应的文件:"+url);  
            }  
            final InputStream fis=in;  
            final String encode=super.getEncoding();  
            Callable<Boolean> call = new Callable<Boolean>() {  
                @Override  
                public Boolean call() {  
                    try {  
                        // 获取许可  
                        semp.acquire();  
                        List<String> csvList = null;  
                        //IOUtils.readLines()是一次性读取整个文件  
                        //readline() 和 .readlines()之间的差异是后者一次读取整个文件,像read()一样。  
                        //readlines()自动将文件内容分析成一个行的列表,  
                        //readline()每次只读取一行,通常比 readlines()慢得多。  
                        //仅当没有足够内存可以一次读取整个文件时,才应该使用readline().  
                        csvList = IOUtils.readLines(fis);  
                        buildExcelDocument(model, csvList, _request, _response);  
                        if (encode == null) {  
                            IOUtils.writeLines(csvList,encode, out);  
                        } else {  
                            IOUtils.writeLines(csvList, encode, out, encode);  
                        }  
                        //Thread.sleep((long) (2000));  
                        return true;  
                    }  catch (Exception e) {  
                        System.out.println(e);  
                        return false;  
                    } finally {  
                        semp.release();  
                    }  
                }  
            };  
            Future<Boolean> future=null;  
            if(!exec.isShutdown()){  
                future= exec.submit(call);  
            }  
           exec.shutdown();  
           if((Boolean) future.get()){  
               System.out.println("success");  
           }else{  
               System.out.print("fail");  
           }  
        }  
          
        @Override  
        public void afterPropertiesSet() throws Exception {  
        }  
    } 

AbstractCsvView.java

Java代码
    import java.io.IOException;  
    import java.io.InputStream;  
    import java.util.ArrayList;  
    import java.util.List;  
    import java.util.Locale;  
    import java.util.Map;  
      
    import javax.servlet.http.HttpServletRequest;  
    import javax.servlet.http.HttpServletResponse;  
      
    import org.apache.commons.io.IOUtils;  
    import org.springframework.core.io.Resource;  
    import org.springframework.core.io.support.LocalizedResourceHelper;  
    import org.springframework.web.servlet.support.RequestContextUtils;  
    import org.springframework.web.servlet.view.AbstractView;  
      
    public abstract class AbstractCsvView  extends AbstractView{  
      
        /** The content type for an csv response */  
        private static final String CONTENT_TYPE = "text/csv";  
          
        /** The extension to look for existing templates */  
        private static final String EXTENSION = ".csv";  
          
        private String lineEnding;  
          
        private String encoding;  
          
        /** The url at which the template to use is located */  
        private String url;  
          
        /** 
         * Default Constructor. 
         * Sets the content type of the view to "text/csv". 
         */  
        public AbstractCsvView() {  
                setContentType(CONTENT_TYPE);  
        }  
          
        /** 
         * Set the URL of the Excel workbook source, without localization part nor extension. 
         */  
        public void setUrl(String url) {  
                this.url = url;  
        }  
          
          
        public void setLineEnding(String lineEnding) {  
                this.lineEnding = lineEnding;  
        }  
      
        public void setEncoding(String encoding) {  
                this.encoding = encoding;  
        }  
          
          
      
        public String getLineEnding() {  
            return lineEnding;  
        }  
      
        public String getEncoding() {  
            return encoding;  
        }  
      
        public String getUrl() {  
            return url;  
        }  
      
        @Override  
        protected boolean generatesDownloadContent() {  
                return true;  
        }  
          
        @Override  
        protected void renderMergedOutputModel(Map<String, Object> model,  
                        HttpServletRequest request, HttpServletResponse response)  
                        throws Exception {  
                // Set the content type and get the output stream.  
                response.setContentType(getContentType());  
                List<String> csvList = null;  
                if (this.url != null) {  
                        InputStream in = getTemplateSource(this.url, request);  
                        csvList = IOUtils.readLines(in);  
                }else{  
                        csvList = new ArrayList<String>();  
                }  
                buildExcelDocument(model, csvList, request, response);  
                if(this.encoding == null){  
                        IOUtils.writeLines(csvList, this.lineEnding, response.getOutputStream());  
                }else{  
                        IOUtils.writeLines(csvList, this.lineEnding, response.getOutputStream(), this.encoding);  
                }  
        }  
      
        protected InputStream getTemplateSource(String url, HttpServletRequest request) throws IOException {  
                LocalizedResourceHelper helper = new LocalizedResourceHelper(getApplicationContext());  
                Locale userLocale = RequestContextUtils.getLocale(request);  
                Resource inputFile = helper.findLocalizedResource(url, EXTENSION, userLocale);  
                  
                // Create the Excel document from the source.  
                if (logger.isDebugEnabled()) {  
                        logger.debug("Loading Excel workbook from " + inputFile);  
                }  
                return inputFile.getInputStream();  
        }  
          
        /** 
         * Subclasses must implement this method to create an csv List 
         * document, given the model. 
         * @param model the model Map 
         * @param csvList 
         * @param request in case we need locale etc. Shouldn't look at attributes. 
         * @param response in case we need to set cookies. Shouldn't write to it. 
         * @throws Exception in case of failure 
         */  
        protected abstract void buildExcelDocument(Map<String, Object> model, List<String> csvList,  
                        HttpServletRequest request, HttpServletResponse response) throws Exception;  
      
    }  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值