最近项目中因为需要用到多线程处理数据,在Java中,我们通常使用两种方式来创建线程:集成Thread类和实现Runnable接口。Java还提供了一个接口,既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,提交任务执行就可以了。