美文网首页
Android线程池解决pthread_create (1040

Android线程池解决pthread_create (1040

作者: Man不经心 | 来源:发表于2018-02-07 18:57 被阅读0次

    首先感谢http://blog.csdn.net/u012702547/article/details/52259529提供的思路,帮我解决了项目中的一个问题。

    问题呈现场景是图片上传约600张图,客服跟我反馈用户传这些图的时候会闪退,追踪代码,找到了问题原因

    pthread_create (1040KB stack) failed: Out of memory

    image

    我的原始代码这样:

    
            ThreadGroup threads = new ThreadGroup("upload");
            for (int j = 0; j < 300; j++) {
               
                Thread thread = new Thread(threads, new Runnable() {
                    @Override
                    public void run() {
                        // 这里是上传图片的代码,我在此替换为log代码
                        Log.d("ThreadGroup", "run: "+j);
                    }
                });
                thread.start();
            }
    
    

    这种方式在我实际测试中发现上传300张以内的图片App是不会crash掉的,半年多以来这段代码也没出现过问题,但是今天用户传了600张图片,这段代码就不ok了,查资料了解到一个问题,当需要new 很多线程时 ,就应该用线程池处理,所以使用线程池改造,改造后的代码如下:

     ThreadPoolExecutor pool = new ThreadPoolExecutor(10,100,10, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>());
            for (int j = 0; j < 1000; j++) {
    
    
                Runnable runnable = new Runnable(){
                    @Override
                    public void run() {
                        Log.d("ThreadPoolExecutor", "run: "+j);
                    }
                };
                pool.execute(runnable);
    
            }
    

    实测上传1000张图片没问题,将改造后的app交给测试人员,问题解决了。关于如何进一步优化这部分代码,需要深入了解线程池和其他多线程技术了,这里进一步拓展线程池相关知识.

    首先,介绍ThreadPoolExecutor的一个常用的构造方法。

    public ThreadPoolExecutor(  
    //核心线程数,除非allowCoreThreadTimeOut被设置为true,否则它闲着也不会死  
    int corePoolSize,   
    //最大线程数,活动线程数量超过它,后续任务就会排队                     
    int maximumPoolSize,   
    //超时时长,作用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时作用于核心线程),闲置超时便被回收             
    long keepAliveTime,                            
    //枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等  
    TimeUnit unit,  
    //缓冲任务队列,线程池的execute方法会将Runnable对象存储起来  
    BlockingQueue<Runnable> workQueue,  
    //线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池创建新线程  
    ThreadFactory threadFactory)  
    

    关于其他线程池,参考了下http://blog.csdn.net/seu_calvin/article/details/52415337的博客,概念讲解比较生动了,这里我直接引用了,感谢博主SEU_Calvin:

    Android中的四类线程池

    Android中最常见的四类具有不同特性的线程池分别为FixThreadPool、CachedThreadPool、ScheduleThreadPool以及SingleThreadExecutor。

    1 FixThreadPool(一堆人排队上公厕)

    public static ExecutorService newFixThreadPool(int nThreads){  
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());  
    }  
    //使用  
    Executors.newFixThreadPool(5).execute(r);  
    

    (1)从配置参数来看,FixThreadPool只有核心线程,并且数量固定的,也不会被回收,所有线程都活动时,因为队列没有限制大小,新任务会等待执行。
    (2)【前方高能,笔者脑洞】FixThreadPool其实就像一堆人排队上公厕一样,可以无数多人排队,但是厕所位置就那么多,而且没人上时,厕所也不会被拆迁,哈哈o(∩_∩)o ,很形象吧。
    (3)由于线程不会回收,FixThreadPool会更快地响应外界请求,这也很容易理解,就好像有人突然想上厕所,公厕不是现用现建的。

    2 SingleThreadPool(公厕里只有一个坑位)

    public static ExecutorService newSingleThreadPool (int nThreads){  
        return new FinalizableDelegatedExecutorService ( new ThreadPoolExecutor (1, 1, 0, TimeUnit. MILLISECONDS, new LinkedBlockingQueue<Runnable>()) );  
    }  
    //使用  
    Executors.newSingleThreadPool ().execute(r);  
    

    (1)从配置参数可以看出,SingleThreadPool只有一个核心线程,确保所有任务都在同一线程中按顺序完成。因此不需要处理线程同步的问题。
    (2)【前方高能,笔者脑洞】可以把SingleThreadPool简单的理解为FixThreadPool的参数被手动设置为1的情况,即Executors.newFixThreadPool(1).execute(r)。所以SingleThreadPool可以理解为公厕里只有一个坑位,先来先上。为什么只有一个坑位呢,因为这个公厕是收费的,收费的大爷上年纪了,只能管理一个坑位,多了就管不过来了(线程同步问题)。

    3 CachedThreadPool(一堆人去一家很大的咖啡馆喝咖啡)

    public static ExecutorService newCachedThreadPool(int nThreads){  
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit. SECONDS, new SynchronousQueue<Runnable>());  
    }  
    //使用  
    Executors.newCachedThreadPool().execute(r);  
    

    (1)CachedThreadPool只有非核心线程,最大线程数非常大,所有线程都活动时,会为新任务创建新线程,否则利用空闲线程(60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能)处理任务。
    (2)任务队列SynchronousQueue相当于一个空集合,导致任何任务都会被立即执行。
    (3)【前方高能,笔者脑洞】CachedThreadPool就像是一堆人去一个很大的咖啡馆喝咖啡,里面服务员也很多,随时去,随时都可以喝到咖啡。但是为了响应国家的“光盘行动”,一个人喝剩下的咖啡会被保留60秒,供新来的客人使用,哈哈哈哈哈,好恶心啊。如果你运气好,没有剩下的咖啡,你会得到一杯新咖啡。但是以前客人剩下的咖啡超过60秒,就变质了,会被服务员回收掉。
    (4)比较适合执行大量的耗时较少的任务。喝咖啡人挺多的,喝的时间也不长。

    4 ScheduledThreadPool(4个里面唯一一个有延迟执行和周期重复执行的线程池)

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){  
    return new ScheduledThreadPoolExecutor(corePoolSize);  
    }  
    public ScheduledThreadPoolExecutor(int corePoolSize){  
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedQueue ());  
    }  
    //使用,延迟1秒执行,每隔2秒执行一次Runnable r  
    Executors. newScheduledThreadPool (5).scheduleAtFixedRate(r, 1000, 2000, TimeUnit.MILLISECONDS);  
    

    (1)核心线程数固定,非核心线程(闲着没活干会被立即回收)数没有限制。
    (2)从上面代码也可以看出,ScheduledThreadPool主要用于执行定时任务以及有固定周期的重复任务。

    代码实践会在后续陆续更新,欢迎大家讨论.

    相关文章

      网友评论

          本文标题:Android线程池解决pthread_create (1040

          本文链接:https://www.haomeiwen.com/subject/mkpazxtx.html