new Thread (() -> { while ( true ) { try { System.out.println( "下载文件" ); Thread.sleep( 1000 * 60 * 5 ); } catch (Exception e) { log.error(e); }
注意的地方是,需要用
try...catch捕获异常,否则如果出现异常,就直接退出循环,下次将无法继续执行了。
但这种方式做的定时任务,只能周期性执行,不能支持定时在某个时间点执行。
特别提醒一下,该线程建议定义成
守护线程,可以通过
setDaemon方法设置,让它在后台默默执行就好。
使用场景:比如项目中有时需要每隔5分钟去
下载某个文件,或者每隔10分钟去读取模板文件
生成静态html页面等等,一些简单的周期性任务场景。
使用
Thread类做定时任务的优缺点:
优点:这种定时任务非常简单,学习成本低,容易入手,对于那些简单的周期性任务,是个不错的选择。
缺点:不支持指定某个时间点执行任务,不支持延迟执行等操作,功能过于单一,无法应对一些较为复杂的场景。
private volatile boolean running = false ; private Thread thread; private CanalConnector canalConnector; public void handle () { //连接canal while (running) { //业务处理 } } public void start () { thread = new Thread ( this ::handle, "name" ); running = true ; thread.start(); } public void stop () { if (!running) { return ;
private CanalService canalService; public void change (ConfigChangeEvent event) { String value = event.getChange( "test.canal.enable" ).getNewValue(); if (BooleanUtils.toBoolean(value)) { canalService.start(); } else {
private static final int QUEUE_MAX_SIZE = 1000 ; private BlockingQueueblockingQueue queue = new LinkedBlockingQueue <>(QUEUE_MAX_SIZE); //生成消息 public boolean push (LoginLog loginLog) { return this .queue.add(loginLog); } //消费消息 public LoginLog poll () { LoginLog loginLog = null ; try { loginLog = this .queue.take(); } catch (InterruptedException e) {
private LoginLogQueue loginLogQueue; public int login (UserInfo userInfo) { //业务处理 LoginLog loginLog = convert(userInfo);ttkqgw.cn
private LoginLogQueue queue; public voit init { new Thread (() -> { while ( true ) { LoginLog loginLog = queue.take();
CompletableFuture userFuture = CompletableFuture.supplyAsync(() -> { getRemoteUserAndFill(id, userInfo); return Boolean.TRUE; }, executor); CompletableFuture bonusFuture = CompletableFuture.supplyAsync(() -> { getRemoteBonusAndFill(id, userInfo); return Boolean.TRUE; }, executor); CompletableFuture growthFuture = CompletableFuture.supplyAsync(() -> { getRemoteGrowthAndFill(id, userInfo); return Boolean.TRUE; }, executor); CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join(); userFuture.get(); bonusFuture.get(); growthFuture.get();ttzb.gs.cn return userInfo;
private static final TransmittableThreadLocal<CurrentUser> THREA_LOCAL = new TransmittableThreadLocal <>(); private String id; private String userName; private String password; private String phone; ... public statis void set (CurrentUser user) { THREA_LOCAL.set(user); } public static void getCurrent () {
public class UserInterceptor extends HandlerInterceptorAdapter { public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { CurrentUser user = getUser(request); if (Objects.nonNull(user)) {
private BusinessConfig businessConfig; CurrentUser user = CurrentUser.getCurrent(); if (Objects.nonNull(user)) { entity.setUserId(user.getUserId()); entity.setUserName(user.getUserName()); } else { entity.setUserId(businessConfig.getDefaultUserId()); entity.setUserName remenzhibo.net(businessConfig.getDefaultUserName());
此外,众所周知,
SimpleDateFormat在java8以前,是用来处理时间的工具类,它是非线程安全的。也就是说,用该方法解析日期会有线程安全问题。
为了避免线程安全问题的出现,我们可以把SimpleDateFormat对象定义成
局部变量。但如果你一定要把它定义成静态变量,可以使用ThreadLocal保存日期,也能解决线程安全问题。
之前见过有些同事写代码时,一个非常有趣的用法,即:使用
MDC传递参数。
MDC是什么?
MDC是
org.slf4j包下的一个类,它的全称是
Mapped Diagnostic Context,我们可以认为它是一个线程安全的存放诊断日志的容器。
MDC的底层是用了
ThreadLocal来保存数据的。
例如现在有这样一种场景:我们使用
RestTemplate调用远程接口时,有时需要在
header中传递
public void init (FilterConfig filterConfig) throws ServletException { } espnzhibo.cn public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { MdcUtil.add(UUID.randomUUID().toString()); System.out.println( "记录请求日志" ); chain.doFilter(request, response); System.out.println( "记录响应日志" ); }
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3109010/ ,如需转载,请注明出处,否则将追究法律责任。