高德一面

发布于 2024-09-27  24 次阅读


抽象算法

有一个消息发送接口MessageService.send(String message),每次消息发送需要耗时2ms;

基于以上接口,实现一个批量发送接口MessageService.batchSend(List<String> messages);

要求如下:

1)一次批量发送消息最大数量为100条

2)批量发送接口一次耗时不超过50ms。

3)要求返回消息发送是否成功的结果。

import java.util.List;
import java.util.concurrent.*;

public class MessageService {

    // 模拟单条消息发送
    public static boolean send(String message) {
        try {
            // 模拟发送消息的时间消耗
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    // 批量发送消息
    public static boolean batchSend(List<String> messages) {
        int maxBatchSize = 100; // 一次批量发送消息最大数量为100条
        int totalMessages = messages.size();
        int threadCount = 4; // 使用4个线程

        if (totalMessages > maxBatchSize) {
            throw new IllegalArgumentException("一次批量发送消息最大数量为100条");
        }

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
        CountDownLatch latch = new CountDownLatch(totalMessages);
        boolean[] results = new boolean[totalMessages];

        // 提交任务
        for (int i = 0; i < totalMessages; i++) {
            final int index = i;
            completionService.submit(() -> {
                boolean result = send(messages.get(index));
                latch.countDown();
                return result;
            });
        }

        // 收集结果
        try {
            for (int i = 0; i < totalMessages; i++) {
                Future<Boolean> future = completionService.poll(50, TimeUnit.MILLISECONDS);
                if (future != null) {
                    results[i] = future.get();
                } else {
                    return false; // 如果在50ms内未完成,返回失败
                }
            }
            executor.shutdown();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            return false;
        }

        for (boolean result : results) {
            if (!result) {
                return false; // 如果任何一条消息发送失败,返回失败
            }
        }

        return true; // 所有消息发送成功
    }

    public static void main(String[] args) {
        // 测试批量发送
        List<String> messages = List.of(new String[100]); // 创建100条空消息
        boolean result = batchSend(messages);
        System.out.println("消息发送结果: " + (result ? "成功" : "失败"));
    }
}

某用户请求某接口信息,控制该接口在单位时间内透出次数,单位时间和次数是提前定义好的

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.Optional;

@Component
public class RateLimitFilter extends OncePerRequestFilter {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final Duration TIME_WINDOW = Duration.ofMinutes(1); // 时间窗口
    private static final long MAX_REQUESTS = 100; // 最大请求次数

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {

        String userId = request.getHeader("userId");
        if (userId == null || "".equals(userId)) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        String key = "requests:user:" + userId + ":" + TIME_WINDOW.toMillis();

        Long currentRequests = Optional.ofNullable(redisTemplate.opsForValue().increment(key))
                                        .map(Long::valueOf).orElse(1L);

        if (currentRequests <= MAX_REQUESTS) {
            filterChain.doFilter(request, response);
        } else {
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            response.getWriter().write("Too many requests");
        }

        // 设置过期时间
        redisTemplate.expire(key, TIME_WINDOW.toMillis(), TimeUnit.MILLISECONDS);
    }
}
人生の意味は平凡ですか、それとも素晴らしいですか?
最后更新于 2024-10-11