前言
我们知道使用Callable可以获得线程中的返回值,它在 java.util.concurrent 包中声明。此接口还包含一个单一的、无参数的cal方法,此方法与Runnable接口的run方法类似,只是它可以返回一个值,并且可以抛出一个已检查的异常。事实上Callable也是Runnable,因为这两个接口都指定了一个有可能被另一个线程执行的类,只是它不受Runnable的限制。
Callable
Callable的使用很简单,多数场景下,大家肯定用它来作为并行查询、计算之类的业务场景,但是如果想统计每个任务的执行耗时,进行相关的任务优化,这个时候通常都是在任务执行前后进行时间的统计计算并输出,这里提供一个简单的工具类在统一收集。
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package java.util.concurrent;
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
AbstractBaseCallable
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* AbstractBaseCallable
*
* @author Duansg
* @version 1.0
* @date 2021/11/5 下午3:24
*/
@Slf4j
public abstract class AbstractBaseCallable<T> implements Callable<T> {
/**
* 获取执行体
*
* @return
*/
protected abstract Supplier<T> getSupplier();
/**
* 获取线程名称
*
* @return
*/
protected abstract String getMethodName();
@Override
public T call() throws Exception {
Stopwatch stopwatch = Stopwatch.createStarted();
try {
return getSupplier().get();
} finally {
log.info("methodName:{},耗时: {} ms", getMethodName(), stopwatch.elapsed(TimeUnit.MILLISECONDS));
stopwatch.stop();
}
}
}
TimerCallable
import cn.gov.zcy.service.thread.base.AbstractBaseCallable;
import lombok.Getter;
import java.util.function.Supplier;
/**
* TimerCallable
*
* @author Duansg
* @version 1.0
* @date 2021/11/5 下午3:15
*/
@Getter
public class TimerCallable<T> extends AbstractBaseCallable<T> {
/**
* 线程名称
*/
public String methodName;
/**
* 执行函数
*/
private Supplier<T> supplier;
/**
* 构造方法
*
* @param methodName 执行的方法名称
* @param supplier 方法体
*/
public TimerCallable(String methodName, Supplier<T> supplier) {
this.methodName = methodName;
this.supplier = supplier;
}
}
Test Unit
import cn.gov.zcy.service.support.ExecutorsSupport;
import cn.gov.zcy.service.thread.TimerCallable;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* TimerCallableTest
*
* @author Duansg
* @version 1.0
* @date 2021/11/8 上午10:07
*/
@Slf4j
public class TimerCallableTest {
private static ExecutorService executorService = ExecutorsSupport.newFixedThreadPool(5, 5, 30, new ThreadFactoryBuilder()
.setNameFormat("TimerCallableTest-test-%d").build());
public static void main(String[] args) {
Future<String> itemMapTask =
executorService.submit(new TimerCallable<>("TimerCallableTest#main", () ->{
log.info("Dunssss");
return "Duansg";
}));
try {
System.out.println(itemMapTask.get());
} catch (Exception e) {
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
}