游戏开发中,通常使用"n段式"代表道具和货币,也经常要把字符串转成Uniparam对象。
系统一定会频繁地生成UniParam对象,所以加入了WeakHashMap作为缓存,还对比了一下性能的差异。
/**
* 统一变参参数配置格式
*
* 定义ID : 参数1 & 参数2 & 参数3 & ...
*
* 定义ID : [10,20] & [测试1,测试2] & 参数3 //表示值在 10,20中随机一个
*
* 定义ID : [10~20] & [0.01~1.00]
* //表示参数1在10到20中随机一个整数,参数2在0.01~1.00随机一个Double(最多小数点后两位)
*
* 嵌套用{} 2003:1&{2003:1&2&3}&3
*
*
* 约定,一般多个UniStrParam用分号(;)隔开 例如, 10056001;10056002;1:1.04&3&测试;2:333&509&测试
*
*
*/
public class UniStrParamFaster {
private List<String> arrayList;
public List<String> getArrayList() {
......
}
// 用于序列化
public UniStrParamFaster() {
}
public UniStrParamFaster(String strUnit) {
......
}
public int GetParamSize() {
return arrayList.size() - 1;
}
public int GetDefineID() {
......
}
public int GetIntParam(int index) {
.......
}
public String GetStrParam(int index) {
......
}
public double GetDoubleParam(int index) {
.......
}
public UniStrParamFaster getUniStrParam(int index) {
.......
}
/**
* 修改第pos个参数为value值
*
* @param pos
* @param value
* @return
*/
public void modify(int pos, double value) {
.......
}
/**
* 修改第pos个参数为value值
*
* @param pos
* @param value
* @return
*/
public void modify(int pos, int value) {
.......
}
/**
* 修改第pos个参数为value值
*
* @param pos
* @param value
*/
public void modify(int pos, String value) {
......
}
public String toString() {
......
}
public String toUniString() {
......
}
//////////////////////////////////////////////测试性能
private static Map<String, UniStrParamFaster> weakCacheMap = new WeakHashMap<>();
private static Map<String, UniStrParamFaster> lruCacheMap = new LruCacheMap<>();
private static AtomicInteger factor = new AtomicInteger(0);
public static String getTestStr() {
StringBuilder str = new StringBuilder().append(factor.getAndIncrement())
.append(":").append(factor.getAndIncrement())
.append("&").append(factor.getAndIncrement())
.append("&").append(factor.getAndIncrement());
return str.toString();
}
public static UniStrParamFaster getParamFromWeakMap(String paramStr) {
UniStrParamFaster paramData = weakCacheMap.get(paramStr);
if (paramData == null) {
paramData = new UniStrParamFaster(paramStr);
weakCacheMap.put(paramStr, paramData);
}
return paramData;
}
public static UniStrParamFaster getParamFromLruMap(String paramStr) {
UniStrParamFaster paramData = lruCacheMap.get(paramStr);
if (paramData == null) {
paramData = new UniStrParamFaster(paramStr);
lruCacheMap.put(paramStr, paramData);
}
return paramData;
}
private final static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static List<String> prepareData() {
int a = 10000;
int b = 1000;
CountDownLatch countDownLatch = new CountDownLatch(a * b);
List<String> data = Collections.synchronizedList(new ArrayList<>(800000));
for (int i = 0; i < a; i++) {
String d = getTestStr();
executorService.execute(() -> {
for (int j = 0; j < b; j++) {
data.add(d);
countDownLatch.countDown();
}
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Collections.shuffle(data);
return data;
}
private static void test1() {
List<String> data = prepareData();
/////////////////////////////////////////////////////////Round1
long startTime = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
final String d = data.get(i);
new UniStrParamFaster(d);
}
System.out.println("new->" + (System.currentTimeMillis() - startTime));
/////////////////////////////////////////////////////////Round2
startTime = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
final String d = data.get(i);
getParamFromWeakMap(d);
}
System.out.println("weakMap->" + (System.currentTimeMillis() - startTime));
/////////////////////////////////////////////////////////Round3
startTime = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
final String d = data.get(i);
getParamFromLruMap(d);
}
System.out.println("lruCacheMap->" + (System.currentTimeMillis() - startTime));
executorService.shutdown();
}
@SuppressWarnings("unused")
private static void test2() {
List<String> data = prepareData();
long startTime = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
String d = data.get(i);
getParamFromWeakMap(d);
}
System.out.println(System.currentTimeMillis() - startTime);
System.gc();
startTime = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
String d = data.get(i);
getParamFromLruMap(d);
}
System.out.println(System.currentTimeMillis() - startTime);
}
@SuppressWarnings("unused")
private static void test3() {
List<String> data = prepareData();
for (int i = 0; i < 31; i++) {
if ((1 << i) > data.size()) {
break;
}
LruCacheMap.setMAX_ENTRIES(1 << i);
lruCacheMap.clear();
long startTime = System.currentTimeMillis();
for (int j = 0; j < data.size(); j++) {
String d = data.get(j);
getParamFromLruMap(d);
}
System.out.println("cache size:" + LruCacheMap.getMAX_ENTRIES() + "->" + (System.currentTimeMillis() - startTime));
}
}
public static void main(String[] args) {
test1();
//test2();
//test3();
}
}
获取10000000次UniParam的结果如图:
LruCacheMap为什么这么快,因为使用了最近最少使用的策略,并且限制了元素的个数:
public class LruCacheMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = 6918023506928428613L;
private static int MAX_ENTRIES = 10000;
/**
* 获得允许存放的最大容量
*
* @return int
*/
public static int getMAX_ENTRIES() {
return MAX_ENTRIES;
}
/**
* 设置允许存放的最大容量
*
* @param int max_entries
*/
public static void setMAX_ENTRIES(int max_entries) {
MAX_ENTRIES = max_entries;
}
/**
* 如果Map的尺寸大于设定的最大长度,返回true,再新加入对象时删除最老的对象
*
* @param Map.Entry eldest
* @return int
*/
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}
public static void main(String[] args) {
Map<Integer, Boolean> map = new LruCacheMap<Integer, Boolean>();
LruCacheMap.setMAX_ENTRIES(10);
System.out.println(map.size());
for (int i = 0; i < 50; i++) {
map.put(i, true);
System.out.println(map.size());
System.out.println(map);
}
}
}