java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Executors创建线程池

使用Java Executors创建线程池的9种方法

作者:写bug写bug

文章主要介绍了 Java 中Executors类创建线程池的 9 种方法,每种方法都详细阐述了实现原理、源代码分析、参数解释、实现过程、特性和使用场景,感兴趣的小伙伴跟着小编一起来看看吧

在 Java 中,Executors类提供了多种静态工厂方法来创建不同类型的线程池。学习线程池时,Executors类不可或缺。掌握其用法、原理和适用场景,有助于在实际项目开发中顺利应用。以下是一些常用方法,我将逐一解释:

这些方法提供了灵活的方式来创建和管理线程池,以满足不同的并发需求。下面,我将详细介绍这 9 种方法的实现和使用场景。

newCachedThreadPool()

newCachedThreadPool方法是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个可缓存线程池,可根据需要动态创建新线程,并终止在一定时间内未使用的空闲线程。

实现原理

源代码分析

在 Java 的java.util.concurrent包中,Executors类并不直接提供newCachedThreadPool的实现。相反,它使用ThreadPoolExecutor构造函数。以下是ThreadPoolExecutor调用的示例:

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

参数解释

实现过程

这种设计使newCachedThreadPool非常适合处理大量短期异步任务,因为它可以动态调整线程数量以适应不同的工作负载。然而,由于它可以创建无限数量的线程,因此必须考虑任务的特性和系统资源限制,以防止资源耗尽。

使用场景

适用于执行许多短期异步任务,特别是当任务的执行时间不确定时。例如,处理 Web 服务器上的大量并发请求或异步日志记录。

newFixedThreadPool(int nThreads)

newFixedThreadPool(int nThreads)方法是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个具有固定线程数的线程池,确保池中的线程数量保持不变。

实现原理

源代码分析

newFixedThreadPool方法通过调用ThreadPoolExecutor类的构造函数来实现。以下是ThreadPoolExecutor调用的示例:

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

参数解释

实现过程

这种设计使newFixedThreadPool非常适合处理大量稳定的任务流,因为它确保任务由固定数量的线程并行执行,避免线程不受控制地增长。然而,由于池大小是固定的,如果任务提交速率超过池的处理能力,任务可能会在队列中长时间等待。因此,使用newFixedThreadPool时,根据任务的特性和预期工作负载设置nThreads非常重要。

使用场景

适用于执行大量长时间运行的任务,且需要固定线程数量的情况。例如,同时运行多个数据加载或数据处理任务,同时限制并发以避免资源过载。

newSingleThreadExecutor()

newSingleThreadExecutor方法是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个单线程执行器,确保所有任务按提交顺序依次执行,使用单个线程。

实现原理

源代码分析

newSingleThreadExecutor方法通过调用ThreadPoolExecutor类的构造函数来实现。以下是ThreadPoolExecutor调用的示例:

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

参数解释

实现过程

这种设计使newSingleThreadExecutor非常适合需要保证任务顺序执行的场景,例如任务有依赖关系或必须按特定顺序执行的情况。此外,由于只有一个线程,它避免了多线程环境中固有的并发问题。然而,单线程执行也限制了并行处理能力;如果一个任务执行时间较长,后续任务可能会经历显著的延迟。因此,使用newSingleThreadExecutor时,考虑任务的性质和顺序执行的要求非常重要。

使用场景

通过使用newSingleThreadExecutor,开发人员可以确保任务按提交顺序执行,而无需管理多个线程的复杂性和潜在问题。

newScheduledThreadPool(int corePoolSize)

newScheduledThreadPool方法是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法用于创建一个固定大小的线程池,支持执行定时和周期性任务。

实现原理

源代码分析

newScheduledThreadPool方法通过调用ScheduledThreadPoolExecutor类的构造函数来实现。以下是调用示例:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

ScheduledThreadPoolExecutorThreadPoolExecutor的子类,专门用于执行定时任务。ScheduledThreadPoolExecutor构造函数的corePoolSize参数定义了池中核心线程的数量。

内部,ScheduledThreadPoolExecutor使用DelayedWorkQueue作为其任务队列,该队列根据任务的预定执行时间对任务进行排序。

实现过程

特性

newScheduledThreadPool方法非常适合需要执行定时任务的场景,例如周期性后台任务或计划在特定时间运行的任务。然而,由于它基于固定大小的线程池,在高负载下,任务可能会排队等待执行。因此,在设计时考虑适当的corePoolSize以满足性能要求非常重要。

使用场景

通过使用newScheduledThreadPool,开发人员可以有效地管理和调度需要在固定间隔或特定时间执行的任务,确保任务由固定数量的线程正确处理。

newWorkStealingPool(int parallelism)

newWorkStealingPool(int parallelism)方法是 Java 8 中引入的java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个工作窃取线程池,可提高并行任务的执行效率,特别是在多处理器系统上。

实现原理

源代码分析

newWorkStealingPool方法通过调用ForkJoinPool类的静态工厂方法来实现。以下是调用示例:

public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool(
        parallelism,
        ForkJoinPool.defaultForkJoinWorkerThreadFactory,
        null, 
        false 
    );
}

参数解释

ForkJoinPool内部使用ForkJoinWorkerThread来执行任务,每个线程都有一个ForkJoinQueue来存储任务。

实现过程

特性

newWorkStealingPool非常适合需要高并发和高吞吐量的场景,特别是在多处理器系统上。然而,由于工作窃取机制,它可能不适合任务执行时间非常短或任务数量非常少的场景,因为窃取本身可能会引入额外的开销。

使用场景

通过使用newWorkStealingPool,开发人员可以有效地管理和执行并行任务,充分利用多核处理器的能力并提高并发应用程序的性能。

newSingleThreadScheduledExecutor()

newSingleThreadScheduledExecutor是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个单线程调度执行器,可调度命令在给定延迟后运行或定期执行。

实现原理

源代码分析

newSingleThreadScheduledExecutor方法通过调用ScheduledThreadPoolExecutor类的构造函数来实现。以下是调用示例:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new ScheduledThreadPoolExecutor(1);
}

这里,ScheduledThreadPoolExecutorExecutorService的一个实现,专门用于执行定时任务。构造函数有一个参数,即核心池大小。将其设置为 1 表示这是一个单线程执行器。

ScheduledThreadPoolExecutor内部使用DelayedWorkQueue作为任务队列。此队列可以根据任务的预定执行时间对任务进行排序。

实现过程

特性

使用场景

privilegedThreadFactory()

privilegedThreadFactory是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个线程工厂,生成具有特权访问权限的线程。这些线程可以访问系统属性、加载系统库和访问文件系统。

实现原理

源代码分析

privilegedThreadFactory方法的实现细节在标准 Java 库中未公开暴露。然而,我们可以通过检查其一般工作方式来理解其功能。以下是privilegedThreadFactory方法可能的调用示例:

public static ThreadFactory privilegedThreadFactory() {
    return new PrivilegedThreadFactory();
}

这里,PrivilegedThreadFactoryExecutors类中的私有静态内部类,实现了ThreadFactory接口。ThreadFactory接口定义了newThread(Runnable r)方法用于创建新线程。

实现过程

示例

虽然我们无法查看privilegedThreadFactory的精确实现,但我们可以提供一个示例实现来演示如何创建特权线程:

public class PrivilegedThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return AccessController.doPrivileged(new PrivilegedAction<>() {
            @Override
            public Thread run() {
                return new Thread(r);
            }
        });
    }
}

在这个示例中,PrivilegedAction是一个实现PrivilegedAction接口的匿名类,其中run方法创建一个新线程。AccessController.doPrivileged方法执行一个特权操作,以确保线程创建过程具有必要的权限。

特性

使用场景

defaultThreadFactory()

defaultThreadFactory是 Java java.util.concurrent包中Executors类的静态工厂方法。此方法创建一个默认线程工厂,生成具有标准属性的线程,没有特殊权限。

实现原理

源代码分析

defaultThreadFactory方法的详细实现未完全暴露,但我们可以从ThreadFactory接口和一些可用的源代码片段推断其行为。

以下是defaultThreadFactory方法的典型调用:

public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}

DefaultThreadFactoryExecutors类中的私有静态内部类,实现了ThreadFactory接口。ThreadFactory接口定义了newThread(Runnable r)方法用于创建新线程。

实现过程

示例

虽然无法看到defaultThreadFactory的精确实现,但我们可以提供一个示例实现来演示如何创建具有默认属性的线程:

public class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s!= null)? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                     poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority()!= Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

在这个示例中,DefaultThreadFactory使用AtomicInteger确保池和线程编号的唯一性。创建的线程名称具有前缀“pool-x-thread-y”,其中 x 和 y 是递增的数字。线程是非守护的,其优先级设置为Thread.NORM_PRIORITY

特性

使用场景

unconfigurableExecutorService(ExecutorService executor)

unconfigurableExecutorService方法在 Java java.util.concurrent包的Executors类中,用于创建一个围绕ExecutorService的不可配置包装器。这意味着一旦包装的ExecutorService被创建,其配置就不能被更改,例如修改池大小或任务队列。

实现原理

源代码分析

unconfigurableExecutorService方法的详细实现未完全暴露,因为它是Executors类的私有方法的一部分。然而,我们可以根据ExecutorService接口和代理机制推断其行为。

以下是unconfigurableExecutorService方法的典型调用:

public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
    return new FinalizableDelegatedExecutorService(executor);
}

FinalizableDelegatedExecutorServiceExecutors类中的私有静态内部类,实现了ExecutorService接口,并将方法调用委托给另一个ExecutorService

实现过程

示例

以下是一个示例实现,演示如何创建一个不可配置的ExecutorService代理:

public class UnconfigurableExecutorService implements ExecutorService {
    private final ExecutorService executor;

    public UnconfigurableExecutorService(ExecutorService executor) {
        this.executor = executor;
    }

    @Override
    public void shutdown() {
        throw new UnsupportedOperationException("Shutdown not allowed");
    }

    @Override
    public List<Runnable> shutdownNow() {
        throw new UnsupportedOperationException("Shutdown not allowed");
    }

    @Override
    public boolean isShutdown() {
        return executor.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return executor.isTerminated();
    }

    @Override
    public void execute(Runnable command) {
        executor.execute(command);
    }
}

在这个示例中,UnconfigurableExecutorService拦截shutdownshutdownNow方法并抛出UnsupportedOperationException。其他方法直接委托给原始的ExecutorService

特性

使用场景

以上就是使用Java Executors创建线程池的9种方法的详细内容,更多关于Java Executors创建线程池的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文