/**
* val 长度目前需要小于 0xff , 否则会出问题
* key内存表示{ next_addr(8), hash(4), val_addr(8), size(1/4), len(?) }
* val内存表示{ size(1/4), len(?) }
*/
public final class Cache2 {
public int cap, size;
public long base;
public final Unsafe unsafe;
public double factor = 0.75;
public Cache2() throws NoSuchFieldException, IllegalAccessException {
this.unsafe = init();
this.cap = 16;
this.base = unsafe.allocateMemory(16 * 8);
fillZero(base, 16 * 8);
}
public Cache2(int cap, double factor) throws NoSuchFieldException, IllegalAccessException {
this.unsafe = init();
this.cap = cap;
this.factor = factor;
this.base = unsafe.allocateMemory(cap * 8L);
fillZero(base, cap * 8L);
}
private Unsafe init() throws NoSuchFieldException, IllegalAccessException {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
}
public void put(String key, String val) {
int len = key.length();
int hash = key.hashCode();
long index = getIndex(hash);
long cur = unsafe.getAddress(index);
long next = 0;
if (0 != cur) {
do {
next = cur;
if (hash == unsafe.getInt(cur + 8)) {
int size = getSize(cur + 8 + 4 + 8, len);
if (size == len) {
long valAddrOffset = cur + 8 + 4;
long this_bytes_addr = valAddrOffset + 8 + (size < 128 ? 1 : 4);
if (checkByte(this_bytes_addr, size, key.getBytes(StandardCharsets.UTF_8))) {
unsafe.freeMemory(unsafe.getAddress(valAddrOffset));
unsafe.putAddress(valAddrOffset, putString(val, 0));
}
}
}
cur = unsafe.getAddress(cur);
} while (cur != 0);
}
if (++size * factor > cap) {
System.out.println("扩容");
}
long keyAddr = putString(key, 8 + 4 + 8);
long valAddr = putString(val, 0);
fillZero(keyAddr, 8L);
unsafe.putInt(keyAddr + 8, hash);
unsafe.putAddress(keyAddr + 8 + 4, valAddr);
unsafe.putAddress(next == 0 ? index : next, keyAddr);
}
public String get(String key) {
int hash = key.hashCode();
long cur = unsafe.getAddress(getIndex(hash));
if (0 == cur) return null;
int len = key.length();
do {
long hashOffset = cur + 8, valAddrOffset = hashOffset + 4, sizeOffset = valAddrOffset + 8;
if (hash == unsafe.getInt(hashOffset)) {
int size = getSize(sizeOffset, len);
if (size == len) {
long this_bytes_addr = sizeOffset + (size < 128 ? 1 : 4);
if (checkByte(this_bytes_addr, size, key.getBytes(StandardCharsets.UTF_8))) {
return getString(unsafe.getAddress(valAddrOffset));
}
}
}
cur = unsafe.getAddress(cur);
} while (cur != 0);
return null;
}
private synchronized long putString(String str, int offset) {
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
int len = bytes.length, strSize = len < 128 ? 1 : 4;
long start = unsafe.allocateMemory(offset + strSize + len) + offset;
if (len < 128) {
unsafe.putByte(start, (byte) len);
} else {
unsafe.putInt(start, len);
}
putByte(bytes, start + strSize, len);
return start - offset;
}
private synchronized String getString(long addr) {
int size;
if ((size = unsafe.getByte(addr)) < 0) {
size = unsafe.getInt(addr);
addr += 4;
} else ++addr;
//TODO 优化byte数组操作为堆外内存赋值
byte[] bytes = new byte[size];
for (int i = 0; i < size; ++i) bytes[i] = unsafe.getByte(addr + i);
return new String(bytes, StandardCharsets.UTF_8);
}
private synchronized void putByte(byte[] bytes, long offsetStart, int len) {
for (int i = 0; i < len; ++i) unsafe.putByte(offsetStart + i, bytes[i]);
}
public synchronized long getIndex(int hash) {
int offset = ((cap - 1) & hash) << 3;
return base + offset;
}
private synchronized int getSize(long address, int len) {
return len < 128 ? unsafe.getByte(address) : unsafe.getInt(address);
}
private synchronized void fillZero(long addr, long cap) {
this.unsafe.setMemory(addr, cap, (byte) 0);
}
private synchronized boolean checkByte(long addr, int size, byte[] bytes) {
for (int i = 0; i < size; ++i) {
if (unsafe.getByte(addr + i) != bytes[i]) {
return false;
}
}
return true;
}
public synchronized void clear() {
for (int i = 0; i < cap; ++i) {
long address = unsafe.getAddress(base + i * 8L);
if (address == 0) continue;
do {
long valAddr = unsafe.getAddress(address + 8 + 4);
unsafe.freeMemory(valAddr);
address = unsafe.getAddress(address);
} while (address != 0);
}
unsafe.freeMemory(base);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Cache2 cache2 = new Cache2();
cache2.put("name", "Administrator");
cache2.put("wcg", "admin");
System.out.println(cache2.get("name"));
System.out.println(cache2.get("wcg"));
cache2.clear();
}
}
java Unsafe实现堆外缓存
最新推荐文章于 2024-03-08 18:23:05 发布