countdown和semaphore是怎么配合的?
根据查询到的一个总数进行除最大同步数,通过这个数创建countdownlunch,通过线程池开线程记录当前的同步日志,去查询相关的数据组装,同步es后对日志进行更新,countdown进行减数,让主线程记录一个主日志表的记录,由于线程池任务数太多会,防止他触发拒绝策略,使用的semaphore控制线程数
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class SyncDb {
public static void main(String[] args) {
SyncDb.run();
}
/**以下是10万数据量的数据同步方案,一般想到开线程用线程池,
但是一般业务中会涉及到你同步后进行一个额外的业务操作,例如本案例就需要记录一个日志,
失败的同步记录日志,可能需要做一个补偿**/
private static void run() {
/**这里用的excutors创建的固定线程池,不好,因为点进去你会看到他的等待队列是无界,
容易oom,需用项目中自定义的线程池**/
ExecutorService executorService = Executors.newFixedThreadPool(100);
List <SyncData> syncData = new ArrayList<>(100000);
syncData.add(null);
int c = syncData.size() / 2000;
CountDownLatch countDownLatch = new CountDownLatch(c);
Semaphore semaphore = new Semaphore(20);
CopyOnWriteArrayList<Object> log = new CopyOnWriteArrayList<>();
for (int i = 0; i < c; i++) {
//为什么用final,保证线程引用的变量不被篡改,带来不可不可预期的错误
int finalI = i;
try {
//信号量一定要放在run方法之前,如果放到里面,到时候会扔到等待队列里去,无法达到控制信号量。
semaphore.acquire();
Runnable runnable = () -> {
try {
countDownLatch.await();
bSave(syncData.subList(finalI, finalI +2000));
} catch (InterruptedException e) {
System.out.println("获取锁超时异常");
}
};
executorService.submit(runnable);
log.add(new Object());
}catch (Exception e){
log.add(new Object());
//异常数据进行后续其他方式补偿
System.out.println("处理异常");
}finally {
countDownLatch.countDown();
semaphore.release();
}
}
saveLog(log);
}
//保存到其他位置
static void bSave(List <SyncData> list){
}
//记录日志
static void saveLog(List <Object> list){
}
}