我正在尝试用Java编写一个简单的算法来选择哪个服务器需要执行一个操作。我想使用一种循环法,但每台服务器上都有一个重量。到目前为止,我编写了以下代码:
public static void main(String[] args) {
// Weight for each server
int x = 1;
int y = 3;
int counterx = 0;
int countery = 0;
for (int ii = 0; ii < 10; ii++) {
counterx++;
countery++;
if (counterx == x) {
System.out.println("Chosen x ");
counterx = 0;
}
if (countery == y) {
System.out.println("Chosen y ");
countery = 0;
}
}
}
因此给定了两个服务器x和y,我已经存储了权重以分配给x和y变量中的每个服务器以及每个服务器的计数器。这似乎有效,但是如果服务器数量增加,代码将变得非常复杂。是否有任何util包可以帮助我根据权重因子确定要调用的服务器?
感谢
答案 0 :(得分:7)
实际上,实现NavigableMap
的类型是理想的,例如TreeMap
。
您需要执行以下操作:
这样,列表中服务器的排序就不重要了。这正是与NavigableMap
方法一起使用的ceilingEntry
。
例如:
public class ServerDetails {
int weight;
String address;
public Server(int weight, String address) {
this.weight = weight;
this.address = address;
}
public int getWeight(){return this.weight;}
public String getAddress(){return this.address;}
}
然后使用以下内容定义服务器池:
public class ServerPool {
Random someRandGen = new Random();
TreeMap<Integer, ServerDetails> pool;
int totalWeight;
public void init(ArrayList<ServerDetails> servers) {
this.pool = new TreeMap<Integer, ServerDetails>();
// create the "weighted selection" list
totalWeight = 0;
for(ServerDetails s : servers) {
// associate each server with the sum of the weights so far
totalWeight += s.getWeight();
this.pool.put(totalWeight, s);
}
}
public ServerDetails getNext() {
int rnd = someRandGen.nextInt(this.totalWeight);
return pool.ceilingEntry(rnd).getValue();
}
}
然后,您可以相应地为池定义添加/删除方法。与以下示例代码一起使用时,每个选择的次数百分比为:
a: 11.1% b: 40.8% c: 19.6% d: 28.5%
代码:
ArrayList<ServerDetails> servers = new ArrayList<ServerDetails>(){{
add(new ServerDetails(10, "a"));
add(new ServerDetails(40, "b"));
add(new ServerDetails(20, "c"));
add(new ServerDetails(30, "d"));
}};
ServerPool serverPool = new ServerPool();
serverPool.init(servers);
for (int i = 0; i < 10000; i++)
System.out.println(serverPool.getNext().getAddress());