在项目实际应用中,由于下载文件内容都比较大,如果同时有很多用户同时在下载,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
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; }
相关推荐
semaphore控制多线程循序执行,网上 找的例子更改的希望对大家有用
│ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致问题的引入.mp4 │ 高并发编程第二阶段07讲、CPU以及CPU缓存的结构,解决高速缓存一致性问题的两种方案介绍.mp4 │ 高并发编程第二阶段08讲、并发编程...
Semaphore 源码解析 通过使用Semaphore可以在高并发场景进行限流控制处理
$信号量请求并发控制(semafaro)以实现咖喱功能
│ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致问题的引入.mp4 │ 高并发编程第二阶段07讲、CPU以及CPU缓存的结构,解决高速缓存一致性问题的两种方案介绍.mp4 │ 高并发编程第二阶段08讲、并发编程...
Semaphore是计数信号量。Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有...
C#语言Semaphore类用法实例,多线程 用于有多个同类型共享资源(比如端口)时,如何协调端口分配给线程访问资源的问题,是一个简单模拟实例(源代码)。
最新2023年Java高并发多线程后端面试题整理, 包含线程池,并发集合,volatile,CountDownLatch,Semaphore,Phaser,AQS,ReentrantLock,ReentrantLock等等问题, 用简洁明了的语言,通俗易懂地阐述了高并发多线程...
CountDownLatch、Semaphore等4大并发工具类详解,并介绍了简单的适用场景。
windows下安装cygwin,编译darknet时缺少的三个头文件,下载后复制到darknet下include文件夹内即可
semaphore开发源码,ansible可视化部署服务程序,支持界面操作。
semaphore完整搭建方案,包括帮助文档、程序源码、可执行程序。按照帮助文档完整搭建可视化ansible部署解决方案
Semaphore的使用及其方法的使用。
java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+...
mutex和semaphore互斥程序实例
Semaphore T-BOX System OverviewPDF,Semaphore T-BOX System Overview
Football_using_semaphore 使用信号量和共享内存模拟足球比赛
Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量。就这一点而言,单纯的synchronized 关键字是实现不了的。 直接看例子吧,这个例子包含3个类,一个是线程类,一个是 Semaphore 关键代码类,一个类是...
关于Android变成中的信号量semaphore,在使用过程中我们往往搞不清楚其信号量的申请和使用。这里主要针对信号量初始值为零的情况做介绍,其他情况不做讨论。初始值为零的情况较少使用,部分代码中的这个情况往往让...
主要介绍了C#使用semaphore来管理异步下载请求的方法,涉及C#使用semaphore实现多线程管理的技巧,需要的朋友可以参考下