Java多线程-四种线程池创建方式

本文详细介绍了Java中四种线程池的创建方式:newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool和newScheduledThreadPool,以及它们的工作原理、优缺点和适用场景。针对每个线程池,文章提供了示例代码并分析了潜在的内存溢出问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一)线程池简介

1、减少线程的频繁创建、销毁。

2、可有效的使用和管理线程,提升资源重复使用率,避免资源不足引起的一些问题。

 

二)newFixedThreadPool

原理:创建一个固定数量大小的线程池,当线程任务数超过固定大小时,未执行的线程任务进行阻塞队列,等待线程池调度。

示例:

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

public class FixedDemo {

    public static void main(String[] args) {
        // 创建一个固定数量的线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);
		
        for (int i = 0; i < 10; i++) {
            final int idx = i;
			
            executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
                @Override
                public void run() {
                    System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
                }
            });
        }
        executor.shutdown(); // 关闭线程池
    }
}

执行效果图:

说明:创建一个固定数量为5的线程池,并创建10个线程任务添加到线程池中,线程池调度器会分配线程来处理任务。

 

源码:Executors类中newFixedThreadPool()方法。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

缺点:该方式创建线程池时,会使用LinkedBlockingQueue无界队列默认构造方法,该默认构造方法大小为Integer.MAX_VALUE,所以当线程任务超多时,可能会堆积大量的请求,从而导致 OOM。但一般的系统直接使用该方式即可。

 

解决方式:直接用new ThreadPoolExecutor的方式创建线程池,指定具体的参数信息。

 

三)newSingleThreadExecutor

原理:创建一个单例线程池, 只存在一个线程运行, 多的线程任务进行阻塞状态。

示例:

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

public class SingleDemo {

    public static void main(String[] args) {
        // 创建一个单例线程池, 只存在一个线程运行, 多的线程任务进行阻塞状态
        ExecutorService executor = Executors.newSingleThreadExecutor();
		
        for (int i = 0; i < 10; i++) {
            final int idx = i;
			
            executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
                @Override
                public void run() {
                    System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
                }
            });
        }
        executor.shutdown(); // 关闭线程池
    }
}

执行效果图:

说明:创建一个单例线程池,并创建10个线程任务添加到线程池中,线程任务被一个一个的顺序执行。

 

源码:Executors类中newSingleThreadExecutor()方法。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

缺点:newFixedThreadPool()方法一样。

 

四)newCachedThreadPool

原理:创建一个缓存线程池,当线程数过大,可回收多余线程,如线程数不足,创建新线程。

示例:

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

public class CachedDemo {

    public static void main(String[] args) {
        // 创建一个缓存线程池, 当线程数过大,可回收多余线程, 如线程数不足, 创建新线程
        ExecutorService executor = Executors.newCachedThreadPool();
		
        for (int i = 0; i < 10; i++) {
            final int idx = i;
			
            executor.execute(new Runnable() { // 创建线程并添加到线程池中, 并启动运行线程
                @Override
                public void run() {
                    System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", 参数idx = " + idx);
                }
            });
        }
        executor.shutdown(); // 关闭线程池
    }
}

执行效果图:

说明:创建一个缓存线程池,并创建10个线程任务添加到线程池中,由于线程运行速度快,会不断创建新线程来执行任务。

 

源码:Executors类中newCachedThreadPool()方法。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

缺点:该方式创建线程时,线程的核心数量大小为0,线程最大数量为Integer.MAX_VALUE,此方式允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

 

解决方式:直接用new ThreadPoolExecutor的方式创建线程池,指定具体的参数信息。

 

五)newScheduledThreadPool

原理:创建一个定时调度线程池,内置一个延迟队列,可按照设定的固定时间周期性的执行任务。

示例:

import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledDemo {

    public static void main(String[] args) {
        // 创建一个定时调度线程池, 内置一个延迟队列, 可按照设定的固定时间周期性的执行任务
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
		
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                long start = System.currentTimeMillis();
                System.out.println("当前线程名: " + Thread.currentThread().getName()
                        + ", scheduleAtFixedRate开始执行时间: " + DateFormat.getTimeInstance().format(new Date()));
                try {
                    Thread.sleep(5000); // 睡眠5秒钟, 方便测试
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long end = System.currentTimeMillis();
	            
                System.out.println("当前线程名: " + Thread.currentThread().getName()
                        + ", scheduleAtFixedRate执行花费时间: " + (end - start) / 1000 + "s");
                System.out.println("当前线程名: " + Thread.currentThread().getName()
                        + ", scheduleAtFixedRate执行完成时间: " + DateFormat.getTimeInstance().format(new Date()));
                System.out.println("----------------------分割线-----------------------");
            }
        }, 1, 5, TimeUnit.SECONDS);
    }
}

执行效果图:

 

说明:创建一个定时调度线程池,添加一个定时调度任务,每隔5秒中执行一遍。

ScheduledFuture<?> scheduleWithFixedDelay
    (Runnable command,  // 要执行的任务
     long initialDelay, // 延迟第一次执行的时间
     long delay,        // 一个执行终止与下一个执行的开始之间的延迟
     TimeUnit unit);    //initialDelay和delay参数的时间单位

// 一个ScheduledFuture代表待完成的任务,其 get()方法将在取消时抛出异常

缺点:newCachedThreadPool()方法一样。

 

识别二维码关注个人微信公众号

本章完结,待续,欢迎转载!
 
本文说明:该文章属于原创,如需转载,请标明文章转载来源!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值