Semaphore控制高并发下载导致内存溢出问题

news/2024/7/8 4:31:38 标签: java, spring, Semaphore

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

java">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;

}

 


http://www.niftyadmin.cn/n/1317116.html

相关文章

Sizeof与Strlen的区别与联系(转)

Sizeof与Strlen的区别与联系 一、sizeof sizeof(...)是运算符&#xff0c;在头文件中typedef为unsigned int&#xff0c;其值在编译时即计算好了&#xff0c;参数可以是数组、指针、类型、对象、函数等。 它的功能是&#xff1a;获得保证能容纳实现所建立的最大对象的字…

underscore.extend与$.extend实例比较分析

underscore.extend实例 <html> <head> </head><meta charset"GBK"><title>extend</title><script type"text/javascript" src"jquery-1.8.3.js"></script><script type"text/javascrip…

【LeetCode每日一题】岛屿的最大面积

给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。 找到给定的二维数组中最大的岛屿面积。(如果没有岛屿&#xff0c;则返回面积为0。) 示例 1: [[0,0,1,0,0,0…

无废话Android之内容观察者ContentObserver、获取和保存系统的联系人信息、网络图片查看器、网络html查看器、使用异步框架Android-Async-Http(4)...

1.内容观察者ContentObserver 如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化&#xff0c;可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者&#xff0c;例子如下&#xff1a; priv…

谈谈浏览器的缓存过期时间

一.浏览器为什么要缓存&#xff1f;什么会缓存下来&#xff1f; 首先当我们访问网页的时候&#xff0c;很多大的图片从服务器上传输过来的时候&#xff0c;试想一下&#xff0c;如果浏览器不把图片缓存下来而是每次都要到服务器去取&#xff0c;那么每次都给服务器和网络造成了…

立即执行函数

立即执行函数 立即执行函数(Immediate Functions) 立即执行函数模式是一种语法&#xff0c;可以让你的函数在定义后立即被执行&#xff0c;比如&#xff1a; (function () { alert(watch out!); }()); 这种模式本质上就是函数表达式(命名的或者匿名的)&#xff0c;在创建后…

JAVA读取、写入、更新CLOB字段

jdbc或PL/SQL中通过insert语句插入数据时&#xff0c;如果有CLOB字段&#xff0c;且插入的数据长度超过4000&#xff0c;且会报ORA-01704字符串文字太长的错。 一.java jdbc方式处理 对于CLOB字段&#xff0c;其实就需要通过流的方式处理&#xff0c;如下是从网上搜集的一些处理…

spring mvc使用@InitBinder标签对表单数据绑定

在SpringMVC中&#xff0c;bean中定义了Date&#xff0c;double等类型&#xff0c;如果没有做任何处理的话&#xff0c;日期以及double都无法绑定。 解决的办法就是使用spring mvc提供的InitBinder标签。 在我的项目中是在BaseController中增加方法initBinder&#xff0c;并使用…