关闭

四大线程池详解

标签: 线程池javaAndroidthread
26467人阅读 评论(16) 收藏 举报
分类:

new Thread 的弊端

首先看一段代码:

/**
 * Created by Zero on 2017/8/30.
 */
public class ThreadTest {
    public static void main(String[] args) {
        while (true) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread());
                }
            }).start();
        }
    }
}
Thread[Thread-0,5,main]
Thread[Thread-4,5,main]
Thread[Thread-3,5,main]
Thread[Thread-6,5,main]
Thread[Thread-7,5,main]
Thread[Thread-2,5,main]
Thread[Thread-1,5,main]
Thread[Thread-8,5,main]
Thread[Thread-9,5,main]
Thread[Thread-5,5,main]
Thread[Thread-10,5,main]
Thread[Thread-11,5,main]
Thread[Thread-12,5,main]
Thread[Thread-13,5,main]
... ...

先说一下此处的打印,第一个参数是当前线程名称,由于线程之间是异步执行,有的还没创建好,有的后来居上就执行完了,导致打印线程的名称会这样,第二个参数是优先级,默认都是5,第三个参数是线程组名称。

如果不停止程序,这段代码会不断创建和销毁线程,直到死机或者OOM,更尴尬的是此处的线程,还无法主动去中断。

上述的线程启动方式在日常开发中经常看到的,但是从性能和优化的角度来说,问题还真不小。

  1. 每次都新建,性能较差(这个在线程池原理中有详细讲解)。
  2. 线程缺乏统一管理,可能无限制的创建线程,互相竞争,会带来一些不必要的麻烦。
  3. 可控性太差,比如定时定期执行,比如线程中断机制

线程池的优点

java提供了四大线程池,主要针对new Thread的弊端讲述优点:

  1. 降低资源消耗,不需要每次都是新建和销毁,性能得到了提高。
  2. 统一管理,可有效控制最大并发量,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  3. 可控性很好,可以定期定时执行、线程中断机制等。

newCachedThreadPool

newCachedThreadPool:创建带有缓存的线程池。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by Zero on 2017/8/30.
 */
public class ThreadTest {
    public static void main(String[] args) {
        test();
    }

    private static void test(){
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {

            cachedThreadPool.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread());
                }
            });
        }
    }
}
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-4,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-6,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-5,5,main]
Thread[pool-1-thread-7,5,main]
Thread[pool-1-thread-7,5,main]
Thread[pool-1-thread-5,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-4,5,main]
Thread[pool-1-thread-7,5,main]
Thread[pool-1-thread-6,5,main]
Thread[pool-1-thread-4,5,main]
... ...

由此可见,上述线程在新建的同时,还有部分线程被回收后再利用,刚刚做了下测试,在每次打印之前加了2ms的延迟,打印的都是“Thread[pool-1-thread-1,5,main]”。

线程池为无限大(其实是Interger. MAX_VALUE),当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程

newFixedThreadPool

newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by Zero on 2017/8/30.
 */
public class ThreadTest {
    public static void main(String[] args) {
        test();
    }

    private static void test(){
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 100; i++) {

            fixedThreadPool.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread());
                }
            });
        }
    }
}
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-2,5,main]
... ...

此处配置最大的线程长度是3,由打印可看出,此处始终在三个线程中执行。

newScheduledThreadPool

newScheduledThreadPool:支持定时和周期性执行的线程池。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by Zero on 2017/8/30.
 */
public class ThreadTest {
    public static void main(String[] args) {
        test();
    }

    private static void test(){
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
        /**
         * 延迟3秒执行
         */
        scheduledThreadPool.schedule(new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread());
            }
        }, 3000, TimeUnit.MILLISECONDS);

        /**
         * 延迟1秒后每3秒执行一次
         */
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread());
            }
        }, 1, 3000, TimeUnit.MILLISECONDS);
    }
}
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-2,5,main]
... ...

此方法无论任务执行时间长短,都是当第一个任务执行完成之后,延迟指定时间再开始执行第二个任务。

在日常开发中,newScheduledThreadPool可以作为timer的替代品,对比timer,newScheduledThreadPool更安全更强大。

newSingleThreadExecutor

newSingleThreadExecutor:从名称上便可以看出,此线程池是一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序。如果这个线程异常结束,会有另一个取代它,保证顺序执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by Zero on 2017/8/30.
 */
public class ThreadTest {
    public static void main(String[] args) {
        test();
    }

    private static void test(){
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 100; i++) {
            singleThreadExecutor.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread());
                }
            });
        }
    }
}

得到的结果会一直是“Thread[pool-1-thread-1,5,main]”。

总结:对于任务量少或者只有一个任务的情况下,此时使用线程池显得高射炮打蚊子了,但是对于任务量多,单个任务处理的时间比较短的情况下,你会对线程池有不一样的体会和好感。

友情推荐:

  1. 线程池原理
  2. 深入Thread.sleep
  3. 多线程中断机制
  4. head first Thread.join()

这里写图片描述

12
6
查看评论

Android—四大线程池的使用介绍

前言 线程池一直是初学者最抵触的东西,由于刚开始学习做项目并不会涉及到线程池的使用,但是不去学习它,心里又好像有个石头一直沉着,一直放心不下,其实是很简单的东西,早晚都要学,不如趁现在吧。由于文章从初学者的角度出发,所以文章显得粗浅,但通俗易懂。废话不多说,开车啦 线程池的简介 ...
  • hxqneuq2012
  • hxqneuq2012
  • 2016-12-16 19:01
  • 233

四种线程池

newCachedThreadPool用法 代码 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestMain { public static...
  • time_hunter
  • time_hunter
  • 2016-11-22 15:11
  • 570

四大线程池详解

new Thread 的弊端首先看一段代码:/** * Created by Zero on 2017/8/30. */ public class ThreadTest { public static void main(String[] args) { while (t...
  • zjxbllg2008
  • zjxbllg2008
  • 2017-09-06 11:34
  • 127

常见的四种线程池和区别

线程池主要解决处理器单元内多个线程执行的问题,能够有效的降低频繁创建和销毁线程所带来的开销。下面简单的介绍一下各个的区别和用处。 (1)fixThreadPool           我的理解这是一个有指定的线程数的线程池,有核心的线程,里面有固定的...
  • qq_34952110
  • qq_34952110
  • 2017-09-25 15:55
  • 110

Android进阶——多线程系列之四大线程池的使用介绍

前言 线程池一直是初学者最抵触的东西,由于刚开始学习做项目并不会涉及到线程池的使用,但是不去学习它,心里又好像有个石头一直沉着,一直放心不下,其实是很简单的东西,早晚都要学,不如趁现在吧。由于文章从初学者的角度出发,所以文章显得粗浅,但通俗易懂。废话不多说,开车啦 线程池的简介 线程池简单...
  • qq_30379689
  • qq_30379689
  • 2016-12-08 22:09
  • 3190

java四大线程池详解

new Thread 的弊端 首先看一段代码: /** * Created by Zero on 2017/8/30. */ public class ThreadTest { public static void main(String[] args) { wh...
  • class_brick
  • class_brick
  • 2017-09-12 17:32
  • 91

四大线程池的用法

  • 2017-07-18 08:59
  • 42.27MB
  • 下载

Executors提供的四种线程池

Executors提供的四种线程池 java.util.concurrent.Executors类,提供了创建四种线程池的方法,相关方法及对应的功能如下: 1、newCachedThreadPool:用来创建一个可缓存线程池,该线程池没有长度限制,对于新的任务,如果有空闲的线程,则使用空闲的...
  • qq_26386171
  • qq_26386171
  • 2016-08-31 11:03
  • 199

java 线程池原理及几种线程池详解

java 线程池原理及几种线程池详解 1、为什么要用线程池? 服务器经常出现处理大量单个任务处理的时间很短而请求的数目却是巨大的请求。 构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务。实际上,对于原型开发这种方法工作得很好,但如果试图部...
  • andychen314
  • andychen314
  • 2016-03-15 17:27
  • 2670

Android线程池详解

在Android开发的时候,当我们需要完成一个耗时操作的时候,通常会新建一个子线程出来,这种方式的线程随处可见,但是这种方式的写法是存在一定问题的,我们知道,在操作系统中,线程是操作系统调度的最小单元,同时线程又不能无限制的产生,并且线程的创建和销毁都会有资源的开销,同时当线程频繁的创建或者销毁的时...
  • cfy137000
  • cfy137000
  • 2016-05-17 15:45
  • 4869
    个人资料
    • 访问:264248次
    • 积分:3000
    • 等级:
    • 排名:第13875名
    • 原创:46篇
    • 转载:0篇
    • 译文:0篇
    • 评论:329条
    QQ交流群

    Android路上

    611566797
    博客专栏
    我的公众号