本文目录导读:

在Java中分配不同场景的权重,常见的有以下几种方案,我分别给出实战代码示例:
简单权重随机选择(基于随机数)
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class WeightedRandomSelector {
// 场景定义
static class Scene {
String name;
int weight;
Scene(String name, int weight) {
this.name = name;
this.weight = weight;
}
}
public static String selectScene(List<Scene> scenes) {
// 计算总权重
int totalWeight = scenes.stream()
.mapToInt(s -> s.weight)
.sum();
// 生成随机数
int random = ThreadLocalRandom.current().nextInt(totalWeight);
// 遍历选择
for (Scene scene : scenes) {
random -= scene.weight;
if (random < 0) {
return scene.name;
}
}
return scenes.get(0).name; // 兜底
}
public static void main(String[] args) {
List<Scene> scenes = Arrays.asList(
new Scene("首页推荐", 50),
new Scene("搜索结果", 30),
new Scene("广告位", 15),
new Scene("活动页", 5)
);
// 模拟100次选择,统计分布
Map<String, Integer> stats = new HashMap<>();
for (int i = 0; i < 10000; i++) {
String selected = selectScene(scenes);
stats.merge(selected, 1, Integer::sum);
}
System.out.println("实际分布情况:");
stats.forEach((k, v) ->
System.out.println(k + ": " + (v / 100.0) + "%"));
}
}
动态权重分配(基于配置文件)
import java.util.*;
import java.util.stream.Collectors;
public class DynamicWeightService {
// 场景配置实体
@lombok.Data
public static class SceneConfig {
private String sceneCode; // 场景编码
private String sceneName; // 场景名称
private int baseWeight; // 基础权重
private int boostWeight; // 加成权重(动态变化)
private Date effectiveDate; // 生效时间
private Date expireDate; // 过期时间
private List<String> conditions; // 触发条件
}
// 动态权重分配器
public class WeightAllocator {
private Map<String, SceneConfig> configMap;
// 根据业务规则计算权重
public int calculateWeight(SceneConfig config, UserContext context) {
int finalWeight = config.getBaseWeight();
// 业务规则1:用户等级加成
if (context.getUserLevel() >= 5) {
finalWeight += config.getBoostWeight() * 1.5;
}
// 业务规则2:时间段加成
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hour >= 20 && hour <= 23) { // 晚间高峰
finalWeight *= 1.3;
}
// 业务规则3:节假日加成
if (isHoliday()) {
finalWeight *= 1.2;
}
// 业务规则4:用户历史行为影响
if (context.getUserHistory().contains(config.getSceneCode())) {
finalWeight *= 0.8; // 降低已展示过的权重
}
return Math.max(finalWeight, 1); // 最低1
}
// 动态选择场景
public SceneConfig selectScene(UserContext context) {
List<SceneConfig> availableScenes = new ArrayList<>();
double totalWeight = 0;
// 收集有效场景并计算权重
Map<SceneConfig, Double> weightMap = new LinkedHashMap<>();
for (SceneConfig config : configMap.values()) {
if (isValid(config, context)) {
double weight = calculateWeight(config, context);
totalWeight += weight;
weightMap.put(config, weight);
}
}
// 加权随机选择
double random = Math.random() * totalWeight;
for (Map.Entry<SceneConfig, Double> entry : weightMap.entrySet()) {
random -= entry.getValue();
if (random <= 0) {
return entry.getKey();
}
}
return weightMap.keySet().iterator().next();
}
private boolean isValid(SceneConfig config, UserContext context) {
Date now = new Date();
return !(now.before(config.getEffectiveDate()) ||
now.after(config.getExpireDate()));
}
private boolean isHoliday() {
// 判断是否节假日
return false; // 简化实现
}
}
@lombok.Data
public static class UserContext {
private int userLevel; // 用户等级
private List<String> userHistory; // 历史浏览
private String deviceType; // 设备类型
// ... 其他上下文属性
}
}
基于策略模式的权重方案
import java.util.*;
public class StrategyWeightAllocator {
// 场景接口
public interface SceneStrategy {
String getSceneName();
int getWeight(SceneContext context);
boolean isSupport(SceneContext context);
}
// 具体场景策略
public static class HomePageStrategy implements SceneStrategy {
@Override
public String getSceneName() { return "homepage"; }
@Override
public int getWeight(SceneContext context) {
int weight = 40;
if (context.isNewUser()) weight += 30;
if (context.getHour() >= 20) weight *= 1.2;
return weight;
}
@Override
public boolean isSupport(SceneContext context) {
return context.getSceneType().equals("browser");
}
}
public static class SearchStrategy implements SceneStrategy {
@Override
public String getSceneName() { return "search"; }
@Override
public int getWeight(SceneContext context) {
if (context.hasSearchIntent()) {
return 80;
}
return 20;
}
@Override
public boolean isSupport(SceneContext context) {
return true;
}
}
// 集中式权重管理
public class WeightManager {
private List<SceneStrategy> strategies;
private Map<String, Integer> dynamicWeights; // 动态调整
public String route(SceneContext context) {
// 收集所有支持的策略
List<SceneStrategy> supported = strategies.stream()
.filter(s -> s.isSupport(context))
.collect(Collectors.toList());
// 计算总权重
int totalWeight = supported.stream()
.mapToInt(s -> s.getWeight(context))
.sum();
// 随机选择
int random = new Random().nextInt(totalWeight);
for (SceneStrategy strategy : supported) {
random -= strategy.getWeight(context);
if (random < 0) {
return strategy.getSceneName();
}
}
return null;
}
// 实时调整权重
public void adjustWeight(String sceneName, int adjustment) {
dynamicWeights.merge(sceneName, adjustment, Integer::sum);
}
}
// 上下文对象
@lombok.Data
public static class SceneContext {
private String sceneType; // 页面类型
private boolean newUser; // 是否新用户
private int hour; // 当前小时
private boolean searchIntent; // 是否有搜索意图
// getters...
}
}
生产环境常用方案(基于配置中心)
import com.alibaba.nacos.api.config.ConfigService;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class RemoteWeightConfig {
// 从配置中心获取权重配置
public class WeightConfigClient {
private ConfigService configService;
private Map<String, Integer> weightCache = new ConcurrentHashMap<>();
// 初始化加载配置
public void init() {
String config = configService.getConfig("scene-weight",
"DEFAULT_GROUP", 5000);
parseConfig(config);
// 订阅变更
configService.addListener("scene-weight", "DEFAULT_GROUP",
new WeightConfigListener());
}
private void parseConfig(String config) {
// 解析 JSON: {"homepage": 0.4, "search": 0.3, ...}
Map<String, Integer> parsed = JSON.parseObject(config);
weightCache.clear();
weightCache.putAll(parsed);
}
// 动态更新缓存
class WeightConfigListener implements Listener {
@Override
public void receiveConfigInfo(String configInfo) {
parseConfig(configInfo);
}
}
// 获取各场景权重
public int getWeight(String scene) {
return weightCache.getOrDefault(scene, 10);
}
}
// A/B 实验权重分配
public class ABTestWeight {
public static class Experiment {
String experimentId;
String groupAWeight; // 40%
String groupBWeight; // 60%
}
public String dispatchUser(String userId) {
int hash = Math.abs(userId.hashCode());
int mod = hash % 100;
if (mod < 40) {
return "control_group";
} else {
return "treatment_group";
}
}
}
}
核心设计建议
权重计算原则
// 统一权重计算接口
public interface WeightCalculator {
// 计算基础权重
int getBaseWeight();
// 计算加成权重
int getBoostWeight(SceneContext context);
// 校验权重有效性
boolean validateWeight(int weight);
// 获取最终权重
default int getFinalWeight(SceneContext context) {
int finalWeight = getBaseWeight() + getBoostWeight(context);
// 应用全局调整因子
if (context.isPeakTime()) {
finalWeight = (int)(finalWeight * 1.2);
}
// 最低限制
return Math.max(finalWeight, 1);
}
}
性能优化建议
// 使用缓存避免重复计算
public class WeightCacheDecorator implements WeightCalculator {
private final WeightCalculator delegate;
private final Map<String, Integer> cache = new ConcurrentHashMap<>();
@Override
public int getFinalWeight(SceneContext context) {
String userId = context.getUserId();
return cache.computeIfAbsent(userId,
key -> delegate.getFinalWeight(context));
}
}
// 使用布隆过滤器快速排除
// 使用并发集合避免竞争
// 热点数据使用本地缓存
选择合适的权重分配方案需要考虑:
- 静态/动态:配置是否经常变化
- 精确度:是否需要精确的百分比控制
- 可观测性:是否需要统计各场景的调用占比
- 分布式:是否需要跨节点一致
建议从简单方案开始,如第一个示例,然后根据业务增长逐步升级到方案2和3,对于生产环境,使用方案4(配置中心+动态调整)是较好的选择。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播