update 优化缓存加锁,清空,设置工作日

This commit is contained in:
AprilWind 2024-08-09 10:22:18 +08:00
parent 1f465c6f04
commit ed5127647c

View File

@ -1,9 +1,12 @@
package org.dromara.common.core.utils; package org.dromara.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/** /**
* 工作日工具类 * 工作日工具类
@ -13,7 +16,12 @@ import java.util.*;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WorkDaysUtils { public class WorkDaysUtils {
private static final Map<Integer, Integer[]> DAYS_IN_YEARS = new HashMap<>(); private static final Map<Integer, Integer[]> DAYS_IN_YEARS = new ConcurrentHashMap<>();
private static final ReentrantLock LOCK = new ReentrantLock();
//工作日
public static final int WORKDAY = 0;
//休息日
public static final int RESTDAY = 1;
/** /**
* 根据开始日期和工作日数计算截止日期 * 根据开始日期和工作日数计算截止日期
@ -34,7 +42,7 @@ public class WorkDaysUtils {
// 循环找到指定的工作日数 // 循环找到指定的工作日数
while (workDays > 0) { while (workDays > 0) {
// 检查当前日期是否是工作日 // 检查当前日期是否是工作日
if (daysArray[endIndex] == 0) { if (daysArray[endIndex] == WORKDAY) {
workDays--; workDays--;
} }
// 结束条件工作日数为零 // 结束条件工作日数为零
@ -79,7 +87,7 @@ public class WorkDaysUtils {
//开始日期年份天 //开始日期年份天
Integer[] daysArray = daysInYear(startYear); Integer[] daysArray = daysInYear(startYear);
for (int i = getDayOfYearIndex(start); i <= getDayOfYearIndex(end); i++) { for (int i = getDayOfYearIndex(start); i <= getDayOfYearIndex(end); i++) {
if (daysArray[i] == 0) { if (daysArray[i] == WORKDAY) {
workDays++; workDays++;
} }
} }
@ -88,7 +96,7 @@ public class WorkDaysUtils {
Integer[] startYearDaysArray = daysInYear(startYear); Integer[] startYearDaysArray = daysInYear(startYear);
int startIndex = getDayOfYearIndex(start); int startIndex = getDayOfYearIndex(start);
for (int i = startIndex; i < startYearDaysArray.length; i++) { for (int i = startIndex; i < startYearDaysArray.length; i++) {
if (startYearDaysArray[i] == 0) { if (startYearDaysArray[i] == WORKDAY) {
workDays++; workDays++;
} }
} }
@ -97,7 +105,7 @@ public class WorkDaysUtils {
Integer[] endYearDaysArray = daysInYear(endYear); Integer[] endYearDaysArray = daysInYear(endYear);
int endIndex = getDayOfYearIndex(end); int endIndex = getDayOfYearIndex(end);
for (int i = 0; i <= endIndex; i++) { for (int i = 0; i <= endIndex; i++) {
if (endYearDaysArray[i] == 0) { if (endYearDaysArray[i] == WORKDAY) {
workDays++; workDays++;
} }
} }
@ -106,7 +114,7 @@ public class WorkDaysUtils {
for (int year = startYear + 1; year < endYear; year++) { for (int year = startYear + 1; year < endYear; year++) {
Integer[] fullYearDaysArray = daysInYear(year); Integer[] fullYearDaysArray = daysInYear(year);
for (Integer integer : fullYearDaysArray) { for (Integer integer : fullYearDaysArray) {
if (integer == 0) { if (integer == WORKDAY) {
workDays++; workDays++;
} }
} }
@ -115,6 +123,13 @@ public class WorkDaysUtils {
return workDays; return workDays;
} }
/**
* 清空所有年份的数据
*/
public static void clearAllData() {
DAYS_IN_YEARS.clear();
}
/** /**
* 获取指定年份的天数数组如果指定年份的数据不存在则生成并缓存数据 * 获取指定年份的天数数组如果指定年份的数据不存在则生成并缓存数据
* *
@ -122,13 +137,25 @@ public class WorkDaysUtils {
* @return 表示一年中每一天的状态数组0 表示工作日1 表示周末 * @return 表示一年中每一天的状态数组0 表示工作日1 表示周末
*/ */
private static Integer[] daysInYear(Integer year) { private static Integer[] daysInYear(Integer year) {
// 先检查缓存
if (DAYS_IN_YEARS.containsKey(year)) { if (DAYS_IN_YEARS.containsKey(year)) {
return DAYS_IN_YEARS.get(year); return DAYS_IN_YEARS.get(year);
} else { }
// 如果缓存中不存在则进行加锁
LOCK.lock();
try {
// 再次检查缓存防止在等待锁期间其他线程已经生成了数据
if (DAYS_IN_YEARS.containsKey(year)) {
return DAYS_IN_YEARS.get(year);
}
// 如果年份数据不存在则生成指定年份的数据 // 如果年份数据不存在则生成指定年份的数据
Integer[] daysArray = generateDaysArray(year); Integer[] daysArray = generateDaysArray(year);
DAYS_IN_YEARS.put(year, daysArray); DAYS_IN_YEARS.put(year, daysArray);
return daysArray; return daysArray;
} finally {
LOCK.unlock();
} }
} }
@ -147,64 +174,36 @@ public class WorkDaysUtils {
for (int i = 0; i < daysInYear; i++) { for (int i = 0; i < daysInYear; i++) {
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
daysArray[i] = (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) ? 1 : 0; daysArray[i] = (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) ? RESTDAY : WORKDAY;
calendar.add(Calendar.DAY_OF_MONTH, 1); calendar.add(Calendar.DAY_OF_MONTH, 1);
} }
//设置为工作日假设用于标记补班的工作日
// 将工作日设置为休息日假设用于标记节假日 updateDaysArray(daysArray, Collections.emptyList(), WORKDAY);
markWorkdaysAsRestdays(daysArray, new ArrayList<>()); //设置为休息日假设用于标记节假日
// 将休息日设置为工作日假设用于标记补班的工作日 updateDaysArray(daysArray, Collections.emptyList(), RESTDAY);
markRestdaysAsWorkdays(daysArray, new ArrayList<>());
return daysArray; return daysArray;
} }
/** /**
* 将工作日设置为休息日假设用于标记节假日 * 根据日期下标更新 daysArray将对应下标的值改为指定值
* *
* @param daysArray 原始的天数数组 * @param daysArray 原始的天数数组
* @param holidays 节假日日期列表 * @param days 要修改的日期列表
* @return 更新后的天数数组 * @param valueToSet 休息日用 1工作日用 0
*/ */
private static Integer[] markWorkdaysAsRestdays(Integer[] daysArray, List<Date> holidays) { private static void updateDaysArray(Integer[] daysArray, List<Date> days, int valueToSet) {
return updateDaysArray(daysArray, holidays, true); if (CollUtil.isEmpty(days)) {
} return;
/**
* 将休息日设置为工作日假设用于标记补班的工作日
*
* @param daysArray 原始的天数数组
* @param holidays 休息日日期列表
* @return 更新后的天数数组
*/
private static Integer[] markRestdaysAsWorkdays(Integer[] daysArray, List<Date> holidays) {
return updateDaysArray(daysArray, holidays, false);
}
/**
* 根据节假日下标更新 daysArray将对应下标的值改为指定值
*
* @param daysArray 原始的天数数组
* @param holidays 节假日日期列表
* @param isHoliday 是否为节假日如果为 true 则表示节假日如果为 false 则表示工作日
* @return 更新后的天数数组
*/
private static Integer[] updateDaysArray(Integer[] daysArray, List<Date> holidays, Boolean isHoliday) {
if (holidays == null || holidays.isEmpty()) {
return daysArray;
} }
// 节假日用 1工作日用 0 // 遍历日期下标数组将对应的 daysArray 元素设置为1
int valueToSet = isHoliday ? 1 : 0; for (Date holiday : days) {
// 遍历节假日下标数组将对应的 daysArray 元素设置为1
for (Date holiday : holidays) {
int index = getDayOfYearIndex(holiday); int index = getDayOfYearIndex(holiday);
// 确保下标在有效范围内 // 确保下标在有效范围内
if (index >= 0 && index < daysArray.length) { if (index >= 0 && index < daysArray.length) {
daysArray[index] = valueToSet; daysArray[index] = valueToSet;
} }
} }
return daysArray;
} }
/** /**