MST

星途 面试题库

面试题:Java线程池线程工厂在复杂分布式系统中的应用与设计

假设你正在设计一个复杂的分布式系统,该系统中有多个不同功能模块且每个模块都有自己独立的线程池。请详细阐述如何设计一个通用的线程工厂,使其能适应不同模块的需求,同时确保系统整体的资源合理利用和性能优化。
27.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 线程工厂接口设计

定义一个通用的线程工厂接口,例如 MyThreadFactory,它应该至少包含一个创建线程的方法:

public interface MyThreadFactory {
    Thread newThread(Runnable r);
}

2. 实现通用线程工厂类

创建一个具体的通用线程工厂类,例如 DefaultMyThreadFactory,来实现上述接口。在这个类中,可以进行一些通用的线程配置,如线程命名、线程优先级设置等。

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

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

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

    @Override
    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;
    }
}

3. 适应不同模块需求

  • 线程命名:在构造函数中传入模块相关的前缀,如 new DefaultMyThreadFactory("module1"),这样创建的线程名就会带有模块标识,方便在日志和调试时区分不同模块的线程。
  • 线程优先级:可以在工厂类中增加设置优先级的方法,或者在构造函数中传入优先级参数,不同模块根据自身业务需求设置不同优先级。例如,对于处理关键业务逻辑的模块,可以将线程优先级设置为 Thread.MAX_PRIORITY,而对于一些辅助性的模块,如日志记录模块,可以设置为较低优先级 Thread.MIN_PRIORITY

4. 资源合理利用和性能优化

  • 线程池大小配置:每个模块根据自身负载和资源需求,合理配置线程池大小。对于 I/O 密集型模块,可以设置较大的线程池大小,因为线程在等待 I/O 操作时会释放 CPU 资源;而对于 CPU 密集型模块,则应设置较小的线程池大小,避免过多线程竞争 CPU 资源。
  • 资源监控与动态调整:通过使用 JMX(Java Management Extensions)等工具,监控每个线程池的运行状态,如线程活跃数、任务队列长度等。根据监控数据,动态调整线程池大小,确保资源的合理利用。例如,当任务队列长度持续增长时,可以适当增加线程池大小;当线程活跃数长时间较低时,可以适当减少线程池大小。
  • 避免线程上下文切换开销:尽量减少线程的创建和销毁次数,通过线程池复用线程。同时,合理分配任务到不同线程池,避免任务在不同线程池之间频繁切换,降低上下文切换开销。

5. 示例代码(使用线程池结合线程工厂)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) {
        MyThreadFactory factory = new DefaultMyThreadFactory("example");
        ExecutorService executorService = new ThreadPoolExecutor(
                5,
                10,
                10L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100),
                factory
        );

        for (int i = 0; i < 20; i++) {
            executorService.submit(() -> {
                System.out.println(Thread.currentThread().getName() + " is running.");
            });
        }

        executorService.shutdown();
    }
}

通过以上设计,能够实现一个通用的线程工厂,满足不同模块的需求,并确保系统整体的资源合理利用和性能优化。