Java代码模拟并发请求和限制访问频率-JDK方法简单实现

时间:2024-05-19 20:13:31

背景:最近面试遇到一道简单的多线程编程题

编程题

(1)客户端Client类10个并发去访问服务端的remote()方法

(2)服务端Server类remote()方法最多允许1秒被访问5次

服务端类Server

import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhougl
 * 2019/4/19
 **/
public class Server {
    // 限制允许访问的线程数的工具类
    private Semaphore s;
    // 过期时间
    private long time;
    // 访问频率
    private int rateLimiter;
    // 使用此工具类来实现线程安全地递增
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public Server(Semaphore s, long time, int rateLimiter) {
        this.s = s;
        this.time = time;
        this.rateLimiter = rateLimiter;
    }

    public String remote(){
        long l = System.currentTimeMillis();
        if(l <= time && atomicInteger.getAndIncrement() < rateLimiter){
            try {
                s.acquire();
                System.out.println("remote方法被调用,调用线程为:"+Thread.currentThread().getName());
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            return "false";
        }
        return "success";
    }
}

客户端类Client

import java.util.concurrent.Callable;

/**
 * @author zhougl
 * 2019/4/19
 **/
public class Client implements Callable{
    private Server server;

    public Client(Server server) {
        this.server = server;
    }

    @Override
    public Object call() throws Exception {
        return server.remote();
    }
}

测试Main类

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

/**
 * @author zhougl
 * 2019/4/19
 **/
public class Main {
    public static void main(String[] args){
        int threadNums = 10;
        int rateLimiter = 5;
        long time = 1000;
        ExecutorService service = Executors.newFixedThreadPool(threadNums);
        CountDownLatch countDownLatch = new CountDownLatch(threadNums);
        Semaphore semaphore = new Semaphore(rateLimiter);

        long currentTimeMillis = System.currentTimeMillis();
        Server server = new Server(semaphore,currentTimeMillis+time,rateLimiter);
        List<Future<?>> result = new ArrayList<>();

        for (int i = 0; i < threadNums; i++) {
//            service.submit();
            Future<?> submit = service.submit(new Client(server));
            result.add(submit);
//            Thread thread = new Thread(new Client(countDownLatch,server));
//            thread.setName("线程-帅哥"+i+"号");
//            thread.start();
            countDownLatch.countDown();
        }

        try {
            countDownLatch.await();
            for (Future<?> future : result) {
                System.out.println(future.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

 调用结果

开启10个客户端线程,调用server端

Java代码模拟并发请求和限制访问频率-JDK方法简单实现

总结

上面的解决方案只使用与单机的场景,性能可能也没那么强。还有其他限流方案,如guava,redis等,后面有遇到再整理。

最近多线程的书看了很多,然而没有实际场景,依然记不住各种并发工具类的使用方法。面试的时候,笔试也写不出来,只有实践才能出真知。希望从这篇文章开始,打开新的多线程之路。