需求介绍
之前遇到了这么一个需求
一个同步的请求,每次请过过来我需要调用底层接口创建配置文件,需要创建4个配置文件
但是这个接口有点慢,每个接口大概1.5S,4个接口6S对一个同步接口显然是不能接受的
我创建成功之后还要回调service的接口
思路
之前遇到这个问题确实难道了我半天,然后去了解了多线程和计数器
- 首先创建计数器
- 多线程同时跑4个接口调用
- 计数器到4时候在回调接口
Java线程会议如下三种方式结束,结束后就处于死亡状态
- run()或者call()方法执行完成,线程正常结束;
- 线程抛出一个未捕获的Exception或Error;
- 直接调用该线程的stop()方法来结束该线程;
所以要捕获异常防止线程异常结束,导致计数器长期阻塞
code
准备工作
//模拟回调接口
public class CallBack {
public static void callBack(){
System.out.println("callBack");
}
}
import java.util.concurrent.TimeUnit;
//模拟创建文件接口
public class HttpMock {
public static void createA() throws Exception {
//模拟等待
TimeUnit.SECONDS.sleep(2);
System.out.println("createA");
}
public static void createB() throws Exception {
TimeUnit.SECONDS.sleep(2);
System.out.println("createB");
}
public static void createC() throws Exception {
TimeUnit.SECONDS.sleep(2);
System.out.println("createC");
}
public static void createD() throws Exception {
TimeUnit.SECONDS.sleep(2);
System.out.println("createD fail");
throw new RuntimeException();
}
}
import java.util.concurrent.*;
//线程池。不要用Executors去创建,可能会出问题的
public class ThreadPoolUtil {
private static volatile ExecutorService threadPool;
public static ExecutorService getThreadPool(){
synchronized (ThreadPoolUtil.class){
if(threadPool == null || threadPool.isShutdown()){
synchronized (ThreadPoolUtil.class){
customThreadPool();
}
}
return threadPool;
}
}
private static void customThreadPool() {
threadPool =
new ThreadPoolExecutor(0,
5,
1L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
}
}
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
public class Demo {
public Boolean test(Integer id ) {
CountDownLatch countDownLatch = new CountDownLatch(4);
//多线程操作集合类,不能用hashset,这里我也想过用atomic,不过想想还是set比较好
CopyOnWriteArraySet copyOnWriteArraySet = new CopyOnWriteArraySet();
//在项目里我也是全部try catch 而且HTTP设置了超时时间
//防止这个线程死了,整个计数器都执行不下去
ThreadPoolUtil.getThreadPool().execute(() -> {
try {
HttpMock.createA();
}catch (Exception e) {
e.printStackTrace();
//把A放到集合里,一会落库,这条失败了
//应该是枚举,但是我这个案列就不写那么详细了
copyOnWriteArraySet.add("A");
}
countDownLatch.countDown();
});
ThreadPoolUtil.getThreadPool().execute(() -> {
try {
HttpMock.createB();
} catch (Exception e) {
e.printStackTrace();
copyOnWriteArraySet.add("B");
}
countDownLatch.countDown();
});
ThreadPoolUtil.getThreadPool().execute(() -> {
try {
HttpMock.createC();
} catch (Exception e) {
e.printStackTrace();
copyOnWriteArraySet.add("C");
}
countDownLatch.countDown();
});
ThreadPoolUtil.getThreadPool().execute(() -> {
try {
HttpMock.createD();
} catch (Exception e) {
e.printStackTrace();
copyOnWriteArraySet.add("D");
}
countDownLatch.countDown();
});
//主线程等待
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(copyOnWriteArraySet.isEmpty()){
CallBack.callBack();
System.out.println("this is ok");
return true;
}
System.out.println("this is fail");
//把集合的数据加上id落库,我们还要做一些处理,你可以选择删除或者其他一些操作
return false;
}
public static void main(String[] args) {
new Demo().test(1);
}
}