jdk提供的四种线程池

一、线程池什么时候用,有什么好处?

“线程池”顾名思义,就是存放线程的池子,这个池子可以存放多少线程取决于采用哪种线程池,取决于有多少并发线程,有多少计算机的硬件资源。使用线程池最直接的好处就是:线程可以重复利用、减少创建和销毁线程所带来的系统资源的开销,提升性能(节省线程创建的时间开销,使程序响应更快)。

二、JDK自带4种的线程池(JDK1.5之后)

2.1、固定线程数的线程池(newFixedThreadPool)

这种线程池里面的线程被设计成存放固定数量的线程,具体线程数可以考虑为CPU核数*N(N可大可小,取决于并发的线程数,计算机可用的硬件资源等)。可以通过下面的代码来获取当前计算机的CPU的核数。

 int processors = Runtime.getRuntime().availableProcessors();

FixedThreadPool 是通过 java.util.concurrent.Executors 创建的 ThreadPoolExecutor 实例。这个实例会复用 固定数量的线程处理一个共享的无边界队列 。任何时间点,最多有 nThreads 个线程会处于活动状态执行任务。如果当所有线程都是活动时,有多的任务被提交过来,那么它会一致在队列中等待直到有线程可用。如果任何线程在执行过程中因为错误而中止,新的线程会替代它的位置来执行后续的任务。所有线程都会一致存于线程池中,直到显式的执行 ExecutorService.shutdown() 关闭。由于阻塞队列使用了LinkedBlockingQueue,是一个无界队列,因此永远不可能拒绝任务。LinkedBlockingQueue在入队列和出队列时使用的是不同的Lock,意味着他们之间不存在互斥关系,在多CPU情况下,他们能正在在同一时刻既消费,又生产,真正做到并行。因此这种线程池不会拒绝任务,而且不会开辟新的线程也不会因为线程的长时间不使用而销毁线程。这是典型的生产者----消费者问题,这种线程池适合用在稳定且固定的并发场景,比如服务器。下面代码给出一个固定线程数的DEMO,每个核绑定了5个线程。

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

public class Test {
    public static void main(String[] args) {
        // 获取计算机有几个核
        int processors = Runtime.getRuntime().availableProcessors();

        // 第一种线程池:固定个数的线程池,可以为每个CPU核绑定一定数量的线程数
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(processors * 5);

        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(new Runnable() {

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

2.2、缓存的线程池(newCachedThreadPool)

核心池大小为0,线程池最大线程数目为最大整型,这意味着所有的任务一提交就会加入到阻塞队列中。当线程池中的线程60s没有执行任务就终止,阻塞队列为SynchronousQueue。SynchronousQueue的take操作需要put操作等待,put操作需要take操作等待,否则会阻塞(线程池的阻塞队列不能存储,所以当目前线程处理忙碌状态时,所以开辟新的线程来处理请求),线程进入wait set。总结下来:①这是一个可以无限扩大的线程池;②适合处理执行时间比较小的任务;③线程空闲时间超过60s就会被杀死,所以长时间处于空闲状态的时候,这种线程池几乎不占用资源;④阻塞队列没有存储空间,只要请求到来,就必须找到一条空闲线程去处理这个请求,找不到则在线程池新开辟一条线程。如果主线程提交任务的速度远远大于CachedThreadPool的处理速度,则CachedThreadPool会不断地创建新线程来执行任务,这样有可能会导致系统耗尽CPU和内存资源,所以在使用该线程池是,一定要注意控制并发的任务数,否则创建大量的线程可能导致严重的性能问题。

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

public class Test {
    public static void main(String[] args) {
        // 缓存线程池,无上限
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        cachedThreadPool.shutdown();
    }
}

2.3、单个线程的线程池(newSingleThreadExecutor)

SingleThreadExecutor是使用单个worker线程的Executor,作为单一worker线程的线程池,SingleThreadExecutor把corePool和maximumPoolSize均被设置为1,和FixedThreadPool一样使用的是无界队列LinkedBlockingQueue,所以带来的影响和FixedThreadPool一样。对于newSingleThreadExecutor()来说,也是当线程运行时抛出异常的时候会有新的线程加入线程池替他完成接下来的任务。创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行,所以这个比较适合那些需要按序执行任务的场景。比如:一些不太重要的收尾,日志等工作可以放到单线程的线程中去执行。日志记录一般情况会比较慢(数据量大一般可能不写入数据库),顺序执行会拖慢整个接口,堆积更多请求,还可能会对数据库造成影响(事务在开启中),所以日志记录完全可以扔到单线程的线程中去,一条条的处理,也可以认为是一个单消费者的生产者消费者模式。

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

public class Test {
    public static void main(String[] args) {
        // 单一线程池,永远会维护存在一条线程
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int j = i;
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":" + j);
                }
            });
        }
        singleThreadPool.shutdown();

    }
}

2.4、固定个数的线程池(newScheduledThreadPool)

相比于第一个固定个数的线程池强大在  ①可以执行延时任务,②也可以执行带有返回值的任务

import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws InterruptedException, ExecutionException{
        // 第四种线程池:固定个数的线程池,相比于第一个固定个数的线程池 强大在 ①可以执行延时任务,②也可以执行
        // 有返回值的任务。
        // scheduledThreadPool.submit(); 执行带有返回值的任务
        // scheduledThreadPool.schedule() 用来执行延时任务.
        // 固定个数的线程池,可以执行延时任务,也可以执行带有返回值的任务。
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        FutureTask<String> ft = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("hello");
                return Thread.currentThread().getName();
            }
        });
        scheduledThreadPool.submit(ft);

        // 通过FutureTask对象获得返回值.
        String result = ft.get();
        System.out.println("result : " + result);

        // 执行延时任务
        scheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " : bobm!");
            }
        }, 3L, TimeUnit.SECONDS);

    }
}

原文地址:https://www.cnblogs.com/shoshana-kong/p/9638559.html

时间: 2024-10-12 02:44:22

jdk提供的四种线程池的相关文章

JDK提供的几种线程池比较

JDK提供的几种线程池 newFixedThreadPool创建一个指定工作线程数量的线程池.每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中. newCachedThreadPool创建一个可缓存的线程池.这种类型的线程池特点是: 1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程. 2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(

Executors 提供的四种线程池

1 .newCahcheThreadPool : 可根据需要创建线程的线程池,如果线程没有可用了,这时候有新任务来了,就创建一个新的线程加入到线程池里.对于在线程池中超过60s未使用的线程,会回收掉资源 2.newSigleTreadPool: 创建一个单线程的线程池,也就是这个线程池中只有一个线程在工作,任务都是串行的,如果运行线程异常结束,会有一个新的线程拉起,这个线程池能保证所有的任务的执行顺序按照用户提交的顺序执行 3.newFiexdTreadPool : 创建固定大小的线程池,每次提

Java四种线程池的学习与总结

在Java开发中,有时遇到多线程的开发时,直接使用Thread操作,对程序的性能和维护上都是一个问题,使用Java提供的线程池来操作可以很好的解决问题. 一.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable(){ @Override public void run(){ //TODO Auto-generatedmethod stub } } ).start(); 那你就out太多了,new Thread的弊端如下:

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 1 2 3 4 5 6 7 new Thread(new

Java四种线程池

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:2015-10-20 22:37:40      阅读:8762      评论:0      收藏:0      [点我收藏+] 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异

JAVA四种线程池实例

1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java 1 2 3 4 5 6 7 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及

Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

原文:http://www.cnblogs.com/zhujiabin/p/5404771.html 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stu

Java ExecutorService四种线程池的简单使用

我们都知道创建一个线程可以继承Thread类或者实现Runnable接口,实际Thread类就是实现了Runnable接口. 到今天才明白后端线程的作用:我们可以开启线程去执行一些比较耗时的操作,类似于前台的ajax异步操作,比如说用户上传一个大的文件,我们可以获取到文件之后开启一个线程去操作该文件,但是可以提前将结果返回去,如果同步处理有可能太耗时,影响系统可用性. 1.new Thread的弊端 原生的开启线程执行异步任务的方式: new Thread(new Runnable() { @O

Executors提供四种线程池

JAVA并发编程--EXECUTORS 线程池的思想是一种对象池的思想,开放一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完毕,对象归还给池.这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源. 代码: http://www.cnblogs.com/chenjingjing/articles/1683745.html 一.固定大小的线程池 newFixedThreadPool  二.单任务线程池 newSingleT