背景:最近面试遇到一道简单的多线程编程题
编程题
(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端
总结
上面的解决方案只使用与单机的场景,性能可能也没那么强。还有其他限流方案,如guava,redis等,后面有遇到再整理。
最近多线程的书看了很多,然而没有实际场景,依然记不住各种并发工具类的使用方法。面试的时候,笔试也写不出来,只有实践才能出真知。希望从这篇文章开始,打开新的多线程之路。