How to Implement Precise Delays in Java Backend Using Timer and Redis

This article explores various strategies for controlling execution timing in Java backend services, comparing Thread.sleep, Timer, and Redis-based expiration techniques, and provides practical code examples and configuration steps for integrating Redis with Spring Boot to achieve reliable delayed processing.

Programmer DD
Programmer DD
Programmer DD
How to Implement Precise Delays in Java Backend Using Timer and Redis

Introduction

When integrating with third‑party services, a token may become invalid after a short period, and a scheduled task that fetches a new token can sometimes run while the token is still being refreshed, causing occasional failures. This article discusses how to delay a request by a short interval (e.g., 800 ms) to avoid such race conditions.

1. Time‑control solutions

1.1 Thread.sleep

The simplest approach is Thread.sleep(800), but in a multithreaded environment an interrupt can cause an exception and suspend the thread, which is not elegant and violates design principles.

1.2 Using java.util.Timer

Java provides a Timer class that can schedule a task after a specified delay. The following example shows a minimal timer implementation:

public class TimmerTest {
    /** Test method */
    public void test() {
        Timer timer = new Timer();
        timer.schedule(new MyTask(), 800);
    }

    public class MyTask extends TimerTask {
        /** Run method */
        @Override
        public void run() {
            System.out.println("输出");
        }
    }
}

This method requires creating a separate TimerTask class, which increases code intrusion and is therefore not ideal.

1.3 Redis‑based delay

Redis offers the EXPIRE command to set a key’s lifetime. By storing a placeholder key with a short TTL, we can achieve a non‑intrusive delay. The advantages are low code intrusion, flexibility through key‑based identifiers, and minimal implementation effort.

2. Redis integration in Spring Boot

2.1 Maven dependencies

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <exclusions>
    <exclusion>
      <groupId>io.lettuce</groupId>
      <artifactId>lettuce-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>

2.2 Redis configuration

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    public RedisTemplate redisTemplateInit() {
        // key serializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // value serializer
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }
}

2.3 Redis utility class

@Component
public class RedisManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisManager.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @SuppressWarnings("unchecked")
    public <T> ValueOperations<String, T> setObject(final String key, final T value) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value);
        return operation;
    }

    @SuppressWarnings("unchecked")
    public <T> ValueOperations<String, T> setObject(final String key, final T value, final long time) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value, time, TimeUnit.SECONDS);
        return operation;
    }

    @SuppressWarnings("unchecked")
    public <T> ValueOperations<String, T> setObjectForMillSeconds(final String key, final T value, final long time) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value, time, TimeUnit.MILLISECONDS);
        return operation;
    }

    @SuppressWarnings("unchecked")
    public Object getObject(final String key) {
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        if (valueOperations == null || !redisTemplate.hasKey(key)) {
            return null;
        }
        return valueOperations.get(key);
    }

    @SuppressWarnings("unchecked")
    public String getString(final String key) {
        String value = "";
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        if (valueOperations != null && redisTemplate.hasKey(key)) {
            Object object = valueOperations.get(key);
            if (object != null) {
                LOGGER.info("--getString--object not empty");
                value = object.toString();
            } else {
                LOGGER.info("--getString--object empty");
            }
        }
        return value;
    }
}

2.4 Using Redis for time control

import com.youjia.orders.redis.RedisManager;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;

public class RedisTest extends OrderProviderApplicationTests {
    @Autowired
    private RedisManager redisManager;

    @Test
    public void test() {
        controlTime("10000001", 10L);
    }

    public void controlTime(String requestId, Long timeOut) {
        if (Objects.isNull(requestId) || Objects.isNull(timeOut)) {
            return;
        }
        final String value = "value";
        redisManager.setObject(requestId, value, timeOut);
        final long startTime = System.currentTimeMillis();
        System.out.println("开始控制时间");
        for (;;) {
            if (Objects.isNull(redisManager.getObject(requestId))) {
                break;
            }
        }
        final long endTime = System.currentTimeMillis();
        final long useTime = endTime - startTime;
        System.out.println("一共耗费时间:" + useTime);
    }
}

3. Conclusion

The article demonstrates common timing‑control challenges in backend development and shows how to solve them elegantly by leveraging middleware such as Redis or built‑in Java utilities, thereby reducing code intrusion and improving reliability.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaredisSpring Boottimerdelay
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.