`
mengqingyu
  • 浏览: 333286 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

(转载)深入浅出的多线程(CachedThreadPool OutOfMemoryError)

阅读更多
    线程池是Conncurrent包提供给我们的一个重要的礼物。使得我们没有必要维护自个实现的心里很没底的线程池了。但如何充分利用好这些线程池来加快我们开发与测试效率呢?当然是知己知彼。本系列就说说对CachedThreadPool使用的一下问题。
    下面是对CachedThreadPool的一个测试,程序有问题吗?
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CachedThreadPoolIssue {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        ExecutorService es = Executors.newCachedThreadPool();
        for(int i = 1; i<8000; i++)
            es.submit(new task());

    }

}
class task implements Runnable{

    @Override
    public void run() {
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
        
    }
    
}

如果对JVM没有特殊的设置,并在Window平台上,那么就会有一下异常的发生:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.addIfUnderMaximumPoolSize(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
    at java.util.concurrent.AbstractExecutorService.submit(Unknown Source)
    at net.blogjava.vincent.CachedThreadPoolIssue.main(CachedThreadPoolIssue.java:19)
看看Doc对该线程池的介绍:
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using ThreadPoolExecutor constructors.

有以下几点需要注意:
1. 指出会重用先前的线程,不错。
2. 提高了短Task的吞吐量。
3. 线程如果60s没有使用就会移除出Cache。

好像跟刚才的错误没有关系,其实就第一句话说了问题,它会按需要创建新的线程,上面的例子一下提交8000个Task,意味着该线程池就会创建8000线程,当然,这远远高于JVM限制了。
注:在JDK1.5中,默认每个线程使用1M内存,8000M !!! 可能吗!!

所以我感觉这应该是我遇到的第一个Concurrent不足之处,既然这么设计,那么就应该在中Doc指出,应该在使用避免大量Task提交到给CachedThreadPool.
可能读者不相信,那么下面的例子说明了他创建的Thread。
在ThreadPoolExecutor提供的API中,看到它提供beforeExecute 和afterExecute两个可以在子类中重载的方法,该方法在线程池中线程执行Task之前与之后调用。所以我们在beforeExexute中查看目前线程编号就可以确定目前的线程数目.
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CachedThreadPoolIssue {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        ExecutorService es = new LogThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        for(int i = 1; i<8000; i++)
            es.submit(new task());

    }

}
class task implements Runnable{

    @Override
    public void run() {
    try {
        Thread.sleep(600000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
        
    }
    
}
class LogThreadPoolExecutor extends ThreadPoolExecutor{

    public LogThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    protected void beforeExecute(Thread t, Runnable r) { 
        System.out.println(t.getName());
    }
    protected void afterExecute(Runnable r, Throwable t) {
    }
    
}

测试结果:
当线程数达到5592是,只有在任务管理器Kill该进程了。

如何解决该问题呢,其实在刚才实例化时就看出来了,只需将
new LogThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
Integer.MAX_VALUE 改为合适的大小。对于该参数的含义,涉及到线程池的实现,将会在下个系列中指出。
当然,其他的解决方案就是控制Task的提交速率,避免超过其最大限制。

本文来自CSDN博客:http://blog.csdn.net/booboo2006/archive/2008/11/10/3266894.aspx
分享到:
评论

相关推荐

    多线程发邮件

    在IT行业中,多线程技术是一项重要的编程技巧,特别是在处理并发任务时,它能显著提升程序的执行效率。本示例“多线程发邮件”就是利用了这一特性,通过并发执行多个邮件发送任务,来加快邮件的发送速度。下面我们将...

    java多线程编程

    在本教程中,我们将深入探讨Java中的多线程设计模式、并发核心编程概念以及线程池的工作原理和种类。 首先,让我们了解什么是多线程。在单线程环境中,程序按照顺序执行任务,而在多线程环境中,可以同时执行多个...

    人工智能-项目实践-多线程-多线程与高并发.zip

    `ExecutorService`允许我们定义线程池的大小和工作模式,例如`FixedThreadPool`用于固定数量的线程,`CachedThreadPool`会缓存线程,而`ScheduledThreadPool`则可以定时执行任务。另外,`CompletableFuture`和`...

    java多线程面试题59题集合

    Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,从而提升系统效率。在面试中,对Java多线程的理解和熟练运用往往成为衡量开发者技能水平的重要标准。以下是对Java多线程面试题59题集合中可能涉及的...

    火山安卓多线程技术源码.rar

    在安卓开发中,多线程技术是至关重要的,它能够帮助...综上所述,"火山安卓多线程技术源码"可能包含了以上各种技术的实现,通过研究这些源码,开发者可以深入理解Android平台上的多线程编程,提高应用性能和用户体验。

    Android多线程

    在Android开发中,多线程是一项至关重要的技术,它使得应用程序能够同时执行多个任务,提升用户体验,特别是对于处理耗时操作如网络请求、大数据...通过多线程的合理运用,可以编写出更加高效、流畅的Android应用程序。

    Java多线程的总结

    这篇总结将深入探讨Java多线程的基础概念、特性以及常见用法,旨在为初学者提供一个全面的学习指南。 一、线程的基本概念 在Java中,线程是程序执行的最小单位,每个线程都有自己的程序计数器、虚拟机栈、本地方法...

    java多线程编程(带目录)

    Java多线程编程是Java开发中的...在"Java多线程编程核心技术_完整版.pdf"这本书中,可能涵盖了上述所有内容,深入探讨了Java多线程编程的各个方面,包括理论、实践案例和最佳实践,帮助开发者熟练掌握这一重要技术。

    Java多线程与并发库高级应用

    在深入探讨Java多线程与并发库的高级应用之前,我们首先需要回顾一下Java多线程的基础概念和技术要点。 ##### 1.1 线程的概念 在计算机科学中,线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是...

    java多线程设计模式

    通过深入学习和实践这些Java多线程设计模式,开发者可以更好地理解和掌握多线程环境下的编程技巧,提高程序的并发性能和稳定性。在实际开发中,应根据具体需求选择合适的设计模式和并发工具,确保代码的正确性和高效...

    Java多线程编程学习.pdf

    本篇文章将深入探讨Java中的多线程编程,包括基本概念、实现方式以及常见问题和解决方案。 一、多线程基础 1.1 线程与进程 线程是操作系统分配CPU时间的基本单位,而进程则是一个独立的执行实体,拥有自己的内存...

    关于线程(java)两天的课件

    线程在Java编程中扮演着至关重要的...总之,本课程将引导你逐步深入Java线程的世界,从基础概念到高级技巧,帮助你构建强大的多线程编程能力。通过学习,你将能更好地应对并发编程中的挑战,提升代码的效率和稳定性。

    Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    Java 多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池) Java 多线程是 Java 语言中的一种并发编程机制,允许程序同时执行多个线程,以提高程序的执行效率和响应速度。 Java 多线程机制提供了...

    多线程模型在 Socket 编程中的应用

    线程池提供了一种线程复用机制,固定数量的线程等待任务,如Java的`FixedThreadPool`,或者根据需求动态调整线程数量如`CachedThreadPool`。线程池可以避免频繁创建和销毁线程,提高系统效率。 6. **线程池的实现*...

    va多线程开发技巧.doc

    Java多线程开发是Java开发中的重要组成部分,尤其在高并发场景下,合理地使用多线程技术可以显著提升程序的执行效率。然而,多线程编程也伴随着一系列挑战,如资源管理、线程安全、任务调度等。以下是对标题和描述中...

    【面试资料】-(机构内训资料)java面试题_多线程(68题).zip

    Java多线程是Java编程中的核心概念,尤其在面试中,它...通过解答这些题目,开发者能深入理解Java多线程的原理,并具备解决实际问题的能力。对于准备Java面试或提升编程能力的人员来说,这68道题无疑是极好的学习材料。

    多线程与线程池技术详解

    在Java编程领域,多线程和线程池技术是核心且关键的概念,它们在现代的高性能、高并发应用中扮演着重要角色。多线程允许应用程序同时执行多个任务,而线程池则是一种管理和控制线程的有效手段,有助于提高系统的效率...

    Java多线程优化方法及使用方式

    Java多线程优化方法及使用方式 Java多线程优化方法及使用方式可以分为以下几个方面: 一、多线程介绍 在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的...

    Java线程 高级使用

    通过以上内容的学习,读者可以深入了解Java线程的高级使用方法,掌握如何在Java程序中高效地管理和控制线程,以及如何解决多线程环境下常见的问题。这对于开发高性能、高可用性的Java应用至关重要。

    多线程(二)

    在Java编程中,多线程是并发处理任务的关键机制,特别是在高性能、高并发的应用场景下。然而,直接创建和管理大量的线程会带来资源浪费和性能瓶颈,这就是线程池的作用所在。线程池通过预先配置好的一组线程来处理...

Global site tag (gtag.js) - Google Analytics