运用ThreadFactory管理自己的线程池

前话

最近项目中因为需要用到多线程处理数据,在Java中,我们通常使用两种方式来创建线程:集成Thread类和实现Runnable接口。Java还提供了一个接口,既ThreadFactory接口,用于创建你自己的线程对象工厂,可以设置线程名称、优先级等属性。

ThreadFactory

为什么要用ThreadFactory来创建线程呢?

  • 自定义具有描述意义的线程名称。如果使用默认的ThreadFactory,它给线程起名字大概规律就是pool-m-thread-n,但是当你分析一个thread dump时,看着这样的名字就很难知道线程的目的。所以使用一个有描述意义的线程名称是分析追踪问题的关键。
  • 设置线程是否是守护线程,默认的ThreadFactory总是提交非守护线程。
  • 设置线程优先级,默认ThreadFactory总是提交的一般优先级线程。

实例:

1、首先我们定义一个自己的线程任务,通过实现Callable(Callable相比Runnable而言可以得到线程的返回值)

/**
 * 线程任务只返回当前线程的名称
 */
public class TestThreadTask implements Callable<String> {

    @Override
    public String call() {
        return Thread.currentThread().getName();
    }
}

2、定义自己的TreadFactory,只需要实现ThreadFactory接口,并重写其中的newTread方法。

public class MyThreadFactory implements ThreadFactory {

    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    /**
     *
     */
    public MyThreadFactory() {
        SecurityManager securityManager = System.getSecurityManager();
        group = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = "chengh-test-thread-";
    }

    /**
     *
     * @param runnable
     * @return
     */
    public Thread newThread(Runnable runnable) {
        Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
        if (thread.isDaemon()) {
            thread.setDaemon(false);
        }
        if (thread.getPriority() != Thread.NORM_PRIORITY) {
            thread.setPriority(Thread.NORM_PRIORITY);
        }
        return thread;
    }
}

3、在spring容器中创建自己的ThreadPool

@Configuration
public class MyThreadPoolConfig {

    /**
     * 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务, 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
     * 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
     */

    private static final int corePoolSize = 10; // 核心线程数(默认线程数)
    private static final int maxPoolSize = 60; // 最大线程数
    private static final int keepAliveTime = 5; // 允许线程空闲时间(单位:默认为秒)

    /**
     *
     * @return
     */
    @Bean("threadPoolExecutor") // bean的名称,默认为首字母小写的方法名
    public ThreadPoolExecutor threadPoolExecutor() {
        return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
                new LinkedBlockingDeque(), new MyThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
    }

}

4、使用,我这里是写在junit里的,只需要注入我们自己的threadPoolExecutor就ok了

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = TestAplication.class)
@WebAppConfiguration
public class UserTest {

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Test
    public void threadTest() {
        List<Future<String>> testThreadTasks = Lists.newArrayList();
        for (int i = 0; i < 100; i++) {
            TestThreadTask task = new TestThreadTask();
            testThreadTasks.add(threadPoolExecutor.submit(task));
        }
        testThreadTasks.forEach(testThreadTask -> {
            try {
                System.out.println(testThreadTask.get()) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            ;
        });
    }
}

打印出来的结果:

chengh-test-thread-1
chengh-test-thread-2
chengh-test-thread-3
chengh-test-thread-4
chengh-test-thread-5
chengh-test-thread-6
chengh-test-thread-7
chengh-test-thread-8
chengh-test-thread-9
chengh-test-thread-10
chengh-test-thread-3
chengh-test-thread-4
chengh-test-thread-2
chengh-test-thread-6
........

总结:

其实使用起来挺简单,只需要创建一个我们自己的线程任务、TreadFactory,再构造自定义的TreadPool,提交任务执行就可以了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值