在项目实际应用中,由于下载文件内容都比较大,如果同时有很多用户同时在下载,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; }
相关推荐
在易语言中,可以通过以下几种方式来防止内存溢出: 1. 使用动态内存分配函数:易语言提供了如`创建内存块`、`扩展内存块`等函数,允许程序在运行时按需分配和释放内存,避免静态分配导致的浪费和溢出风险。 2. ...
- **栈内存与栈溢出**:每个线程都有独立的栈,过多的递归或线程可能导致栈溢出。 - **线程优先级**:虽然Java线程优先级可以设置,但在实际应用中并不推荐依赖它来调整并发行为。 7. **分布式并发** - **分布式...
Servlet多线程问题是一个常见的挑战,尤其是在高并发的服务器环境中。这里我们将深入探讨Servlet与多线程的相关知识点,以及如何解决可能遇到的问题。 首先,理解Servlet生命周期中的多线程模型至关重要。当一个...
大图片如果直接加载到内存中,可能会导致内存溢出(OOM)问题。因此,我们需要通过缩放图片来减少内存消耗。使用`BitmapFactory.Options`类的`inSampleSize`参数可以指定图片的缩小比例,以降低内存占用。例如,设置...
线程安全问题(如死锁、活锁、饥饿等)需要谨慎处理,合理使用并发工具类如Semaphore、CountDownLatch、CyclicBarrier等。 8. **线程池**: Java的ExecutorService和ThreadPoolExecutor提供了线程池管理,可以有效...
不当的内存管理可能导致内存溢出。理解Java内存模型,合理设置堆大小,避免创建过大的对象,及时清理不再使用的对象,使用WeakReference和SoftReference管理对象,可以帮助防止内存溢出。 以上仅是部分常见的Java ...
了解内存溢出的原因和如何调试和处理这些问题对于Java开发人员非常重要。 #### 性能评估与诊断 在开发和维护Java应用程序时,性能评估和问题诊断是不可或缺的。了解如何使用top、vmstat、free、df、iostat、ifstat...
控制访问速率的另一种算法是漏桶算法,其原理类似固定容量的桶,水(请求)以一定速率流入,当流入速度过快导致水溢出时,就限制了数据的传输速率。漏桶算法能够对数据传输速率实现硬性限制,适用于对流量控制要求高...
5. **Semaphore**: 信号量用于限制同时访问共享内存的进程数量,避免资源竞争导致的问题。 在"Swoole Shared Memory-master"这个压缩包中,我们可以期待找到以下内容: - `README.md`: 项目介绍、安装指南、使用...
- **避免过度使用线程**:创建过多的线程不仅会导致上下文切换频繁,增加系统开销,还可能引起内存溢出等问题。 - **利用并发框架**:利用成熟的并发框架如`Java.util.concurrent`包中的工具类可以大大简化并发编程...
竞态条件(Race Conditions)是在多线程编程中常见的问题,当两个或多个线程并发访问同一资源并依赖于特定的执行顺序时,可能会导致未定义的行为。同步原语如mutex和semaphore可以帮助解决这类问题,确保对共享资源...
15. **并发编程**:Java并发工具类如Semaphore、CyclicBarrier等,以及并发集合如ConcurrentHashMap,都是解决多线程环境下问题的关键。 以上只是部分可能包含在"Java五百篇"中的主题,每个主题下都可能有几十甚至...
缓冲区溢出是指程序在向缓冲区写入数据时超过了其实际容量,导致数据溢出到缓冲区之外的内存区域。这可能导致数据破坏、程序崩溃,甚至恶意攻击者利用该漏洞执行任意代码,危害系统的安全性。 以上就是针对操作系统...
- **程序计数器**:记录当前线程执行的字节码指令的行号,用于线程切换后的恢复,是线程私有的,不会出现内存溢出(OutOfMemoryError)。 - **Java虚拟机栈**:每个线程都有一个栈,用于存储方法调用的栈帧,包含...
例如,可以使用ThreadPoolExecutor来创建一个具有固定大小线程池的ExecutorService,这样可以确保系统不会因创建过多线程而导致内存溢出。 另外,Java还提供了其他高级特性来处理并发和多线程问题,如: - **同步...
内存溢出异常指的是程序在申请内存时,没有足够的空间分配给请求的内存区域,导致JVM无法完成存储操作。常见的内存溢出包括:堆溢出、栈溢出、方法区溢出。 #### 垃圾收集器 垃圾收集器主要作用是回收JVM堆中的...
通常情况下,过多的线程会导致内存溢出或其他性能问题。 - **线程池**: 使用线程池是一种更高效地管理线程的方式。`Executors.newCachedThreadPool()`是一个常用的创建线程池的方法,它可以根据实际需求动态调整线程...
通过调整JVM的堆大小、新生代与老年代的比例、垃圾收集器类型等参数,可以优化系统资源的分配,避免内存溢出或频繁的垃圾回收导致的系统停顿。 其次,代码级别的优化也是不可或缺的。这包括减少不必要的对象创建,...
- **缓冲溢出**:需要注意内存管理,防止缓冲区过大导致内存溢出,或过小无法接收完整数据。 3. **保存到本地文件**: - **文件I/O操作**:在Linux中,可以使用`open`打开文件,`write`写入数据,`close`关闭文件...
9. **性能监控**:使用JConsole、VisualVM等工具监控JVM的运行状态,可以及时发现潜在问题,如CPU过高、内存溢出等。 10. **日志与调试**:良好的日志记录习惯可以帮助定位问题。学会使用断点、步进、查看堆栈信息...