玩家缓存清理线程优化

master_0.05_aqlm
grimm 2024-03-22 15:30:35 +08:00
parent 2b8bd96c28
commit 9c8b2e2aa7
6 changed files with 216 additions and 194 deletions

View File

@ -130,6 +130,12 @@ public class TimeUtils {
return _calendar.getTimeInMillis();
}
public static Date stringToDate(String dateString) {
DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(ymdhms_Format_new);
LocalDateTime localDateTime = LocalDateTime.parse(dateString, FORMATTER);
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
/**
* yyyyMMDDHHmmss
*/

View File

@ -17,10 +17,9 @@ public class OnlineUserManager {
public static Map<Integer,Integer> tokenMap = new ConcurrentHashMap<>();
public static void checkOnline(){
UserManager.adjustCacheBasedOnCurrentLoad();
}
// public static void checkOnline(){
// UserManager.adjustCacheBasedOnCurrentLoad();
// }
public static void userOffline(int uid) {
if(sessionMap.containsKey(uid)){

View File

@ -44,7 +44,7 @@ public class UserManager {
// 玩家数据缓存
private static final int maxMemoryLimit = 1000; // 最大内存限制,实际应由您的服务器规格决定
private static final long LIVE_TIME = 60 * 60 * 1000L;// 离线玩家缓存保留时间(毫秒)
private static final DynamicLRUCache<Integer, User> userMap = new DynamicLRUCache<>(100, LIVE_TIME);
private static final DynamicLRUCache<Integer, User> userMap = new DynamicLRUCache<>(600, LIVE_TIME);
private static final AtomicInteger login_f_num = new AtomicInteger(0);//登陆计数
@ -72,6 +72,7 @@ public class UserManager {
// 这个方法可能由定时任务或某种监控服务调用
public static void adjustCacheBasedOnCurrentLoad() {
// 调用缓存的调整方法来根据在线玩家数量调整缓存大小
Thread.currentThread().setName("user_cache_clean");
userMap.shrinkToFit();
}

View File

@ -5,6 +5,7 @@ import com.ljsd.IManager;
import com.ljsd.jieling.logic.dao.UserManager;
import com.ljsd.jieling.thread.task.*;
import com.ljsd.jieling.util.ConfigurableApplicationContextManager;
import com.ljsd.jieling.util.TaskKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.TimeUtils;
@ -32,7 +33,7 @@ public class ThreadManager implements IManager {
public void init() {
mongoDataHandlerTask = ConfigurableApplicationContextManager.getBean(MongoDataHandlerTask.class);
mongoDataHandlerTask = ConfigurableApplicationContextManager.getBean(MongoDataHandlerTask.class);
// dataReportTask = ConfigurableApplicationContextManager.getBean(DataReportTask.class);
itemLogTask = ConfigurableApplicationContextManager.getBean(ItemLogTask.class);
@ -118,9 +119,9 @@ public class ThreadManager implements IManager {
// 每秒钟任务
scheduledFutureSets.add(scheduledExecutor.scheduleAtFixedRate(new SecondsTask(), delayForMinute + 10, 1, TimeUnit.SECONDS));
// 战力任务
scheduledFutureSets.add(scheduledExecutor.scheduleAtFixedRate(new ForceRankTask(), 60,5, TimeUnit.SECONDS));
TaskKit.scheduleAtFixedRate(new ForceRankTask(), 60,5, TimeUnit.SECONDS);
// 每小时减容用户缓存
scheduledFutureSets.add(scheduledExecutor.scheduleAtFixedRate(UserManager::adjustCacheBasedOnCurrentLoad, 10, 60, TimeUnit.MINUTES));
TaskKit.scheduleAtFixedRate(UserManager::adjustCacheBasedOnCurrentLoad, 3, 1, TimeUnit.HOURS);
// 定时重启线程池
scheduledFutureSets.add(scheduledExecutor.scheduleAtFixedRate(new Thread(() -> {
long lastMilis = System.currentTimeMillis();

View File

@ -100,7 +100,13 @@ public class DynamicLRUCache<K, V> {
if (cache.size() < maxSize / 2 && maxSize > 100) {
maxSize /= 2; // 缩小缓存容量
}
cache.entrySet().removeIf(entry -> isEntryExpired(entry.getValue()));
Iterator<Map.Entry<K, TimedCacheEntry<V>>> iterator = cache.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<K, TimedCacheEntry<V>> entry = iterator.next();
if (isEntryExpired(entry.getValue())) {
iterator.remove(); // 使用迭代器来安全移除条目
}
}
} finally {
lock.writeLock().unlock();
}

View File

@ -1,195 +1,204 @@
package com.ljsd.jieling.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.TimeUtils;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
*
*
* @author <a href="mailto:biezhi.me@gmail.com" target="_blank">biezhi</a>
* @since 1.0
*/
@Deprecated
public abstract class TaskKit {
//
// private static final Logger LOGGER = LoggerFactory.getLogger(TaskKit.class);
//
// private static ScheduledThreadPoolExecutor taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
// private static List<Timer> timerList = new ArrayList<>();
//
// /**
// * 立即启动,并以固定的频率来运行任务。后续任务的启动时间不受前次任务延时影响。
// * @param task 具体待执行的任务
// * @param periodSeconds 每次执行任务的间隔时间(单位秒)
// */
// public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long periodSeconds) {
// return scheduleAtFixedRate(task, 0, periodSeconds, TimeUnit.SECONDS);
// }
//
// /**
// * 在指定的延时之后开始以固定的频率来运行任务。后续任务的启动时间不受前次任务延时影响。
// * @param task 具体待执行的任务
// * @param initialDelay 首次执行任务的延时时间
// * @param period 每次执行任务的间隔时间(单位秒)
// * @param unit 时间单位
// */
// public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
// return taskScheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
// }
//
// /**
// * 在指定的时间点开始以固定的频率运行任务。后续任务的启动时间不受前次任务延时影响。
// * @param task 具体待执行的任务
// * @param startTime 首次运行的时间点,支持 "yyyy-MM-dd HH:mm:ss" 格式
// * @param period 每次执行任务的间隔时间
// * @param unit 时间单位
// */
// public static void scheduleAtFixedRate(Runnable task, String startTime, long period, TimeUnit unit) throws ParseException {
// Date dt = TimeUtils.dateFormat(startTime);
// scheduleAtFixedRate(task, dt, period, unit);
// }
//
// /**
// * 在指定的时间点开始以固定的频率运行任务。后续任务的启动时间不受前次任务延时影响。
// * @param task 具体待执行的任务
// * @param startTime 首次运行的时间点
// * @param period 每次执行任务的间隔时间
// * @param unit 时间单位
// */
// public static void scheduleAtFixedRate(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
// final Timer timer = new Timer();
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// taskScheduler.scheduleAtFixedRate(task, 0, period, unit);
// timer.cancel();
// timerList.remove(timer);
// }
// }, startTime);
// timerList.add(timer);
// }
//
// /**
// * 在指定的时间点开始一次任务。
// * @param task 具体待执行的任务
// * @param startTime 首次运行的时间点
// * @param unit 时间单位
// */
// public static void scheduleOne(final Runnable task, long startTime, final TimeUnit unit) {
// taskScheduler.schedule(task,startTime,unit);
// }
//
// /**
// * 立即启动,两次任务间保持固定的时间间隔
// * @param task 具体待执行的任务
// * @param periodSeconds 两次任务的间隔时间(单位秒)
// */
// public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long periodSeconds) {
// return scheduleWithFixedDelay(task, 0, periodSeconds, TimeUnit.SECONDS);
// }
//
// /**
// * 在指定的延时之后启动,两次任务间保持固定的时间间隔
// * @param task 具体待执行的任务
// * @param initialDelay 首次执行任务的延时时间
// * @param period 两次任务的间隔时间(单位秒)
// * @param unit 时间单位
// */
// public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long period, TimeUnit unit) {
// return taskScheduler.scheduleWithFixedDelay(task, initialDelay, period, unit);
// }
//
// /**
// * 在指定的时间点启动,两次任务间保持固定的时间间隔
// * @param task 具体待执行的任务
// * @param startTime 首次运行的时间点,支持 "yyyy-MM-dd HH:mm:ss" 格式
// * @param period 两次任务的间隔时间
// * @param unit 时间单位
// */
// public static void scheduleWithFixedDelay(Runnable task, String startTime, long period, TimeUnit unit) throws ParseException {
// Date dt = TimeUtils.dateFormat(startTime);
// scheduleWithFixedDelay(task, dt, period, unit);
// }
//
// /**
// * 在指定的时间点启动,两次任务间保持固定的时间间隔
// * @param task 具体待执行的任务
// * @param startTime 首次运行的时间点
// * @param period 两次任务的间隔时间
// * @param unit 时间单位
// */
// public static void scheduleWithFixedDelay(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
// final Timer timer = new Timer();
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// taskScheduler.scheduleWithFixedDelay(task, 0, period, unit);
// timer.cancel();
// timerList.remove(timer);
// }
// }, startTime);
// timerList.add(timer);
// }
//
// /**
// * 调整线程池大小
// * @param threadPoolSize
// */
// public static void resizeThreadPool(int threadPoolSize) {
// taskScheduler.setCorePoolSize(threadPoolSize);
// }
//
// /**
// * 返回定时任务线程池,可做更高级的应用
// * @return
// */
// public static ScheduledThreadPoolExecutor getTaskScheduler() {
// return taskScheduler;
// }
//
// /**
// * 关闭定时任务服务
// * <p>系统关闭时可调用此方法终止正在执行的定时任务一旦关闭后不允许再向线程池中添加任务否则会报RejectedExecutionException异常</p>
// */
// public static void depose() {
// int timerNum = timerList.size();
// //清除Timer
// synchronized (timerList) {
// for (Timer t: timerList)
// t.cancel();
// timerList.clear();
// }
//
// List<Runnable> awaitingExecution = taskScheduler.shutdownNow();
// LOGGER.info("Tasks stopping. Tasks awaiting execution: {}", timerNum + awaitingExecution.size());
// }
//
// /**
// * 重启动定时任务服务
// */
// public static void reset() {
// depose();
// taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
// }
//
// /**
// * 根据 Java 虚拟机可用处理器数目返回最佳的线程数。<br>
// * 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)其中阻塞系数这里设为0.9
// */
// private static int getBestPoolSize() {
// int num = 0;
// try {
// // JVM可用处理器的个数
// final int cores = Runtime.getRuntime().availableProcessors();
// // 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)
// // TODO 阻塞系数是不是需要有个setter方法能让使用者自由设置呢
// num = (int)(cores / (1 - 0.9));
// if (num > 8) {
// num = 8;
// }
// }
// catch (Throwable e) {
// // 异常发生时姑且返回10个任务线程池
// num = 5;
// }
// LOGGER.info("定时器线程启动,线程数量:{}",num);
// return num;
// }
private static final Logger LOGGER = LoggerFactory.getLogger(TaskKit.class);
private static ScheduledThreadPoolExecutor taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
private static List<Timer> timerList = new ArrayList<>();
/**
*
* @param task
* @param periodSeconds ()
*/
public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long periodSeconds) {
return scheduleAtFixedRate(task, 0, periodSeconds, TimeUnit.SECONDS);
}
/**
*
* @param task
* @param initialDelay
* @param period ()
* @param unit
*/
public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
return taskScheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
}
/**
*
* @param task
* @param startTime , "yyyy-MM-dd HH:mm:ss"
* @param period
* @param unit
*/
public static void scheduleAtFixedRate(Runnable task, String startTime, long period, TimeUnit unit) {
Date dt = TimeUtils.stringToDate(startTime);
scheduleAtFixedRate(task, dt, period, unit);
}
/**
*
* @param task
* @param startTime
* @param period
* @param unit
*/
public static void scheduleAtFixedRate(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
taskScheduler.scheduleAtFixedRate(task, 0, period, unit);
timer.cancel();
timerList.remove(timer);
}
}, startTime);
timerList.add(timer);
}
/**
*
* @param task
* @param startTime
* @param unit
*/
public static void scheduleOne(final Runnable task, long startTime, final TimeUnit unit) {
taskScheduler.schedule(task,startTime,unit);
}
/**
*
* @param task
* @param periodSeconds ()
*/
public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long periodSeconds) {
return scheduleWithFixedDelay(task, 0, periodSeconds, TimeUnit.SECONDS);
}
/**
*
* @param task
* @param initialDelay
* @param period ()
* @param unit
*/
public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long period, TimeUnit unit) {
return taskScheduler.scheduleWithFixedDelay(task, initialDelay, period, unit);
}
/**
*
* @param task
* @param startTime , "yyyy-MM-dd HH:mm:ss"
* @param period
* @param unit
*/
public static void scheduleWithFixedDelay(Runnable task, String startTime, long period, TimeUnit unit) throws ParseException {
Date dt = TimeUtils.stringToDate(startTime);
scheduleWithFixedDelay(task, dt, period, unit);
}
/**
*
* @param task
* @param startTime
* @param period
* @param unit
*/
public static void scheduleWithFixedDelay(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
taskScheduler.scheduleWithFixedDelay(task, 0, period, unit);
timer.cancel();
timerList.remove(timer);
}
}, startTime);
timerList.add(timer);
}
/**
* 线
* @param threadPoolSize
*/
public static void resizeThreadPool(int threadPoolSize) {
taskScheduler.setCorePoolSize(threadPoolSize);
}
/**
* 线
* @return
*/
public static ScheduledThreadPoolExecutor getTaskScheduler() {
return taskScheduler;
}
/**
*
* <p>线RejectedExecutionException</p>
*/
public static void depose() {
int timerNum = timerList.size();
//清除Timer
synchronized (timerList) {
for (Timer t: timerList)
t.cancel();
timerList.clear();
}
List<Runnable> awaitingExecution = taskScheduler.shutdownNow();
LOGGER.info("Tasks stopping. Tasks awaiting execution: {}", timerNum + awaitingExecution.size());
}
/**
*
*/
public static void reset() {
depose();
taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
}
/**
* Java 线<br>
* 线 = CPU / (1 - )0.9
*/
private static int getBestPoolSize() {
int num = 0;
try {
// JVM可用处理器的个数
final int cores = Runtime.getRuntime().availableProcessors();
// 最佳的线程数 = CPU可用核心数 / (1 - 阻塞系数)
// TODO 阻塞系数是不是需要有个setter方法能让使用者自由设置呢
num = (int)(cores / (1 - 0.9));
if (num > 8) {
num = 8;
}
}
catch (Throwable e) {
// 异常发生时姑且返回10个任务线程池
num = 5;
}
LOGGER.info("定时器线程启动,线程数量:{}",num);
return num;
}
}