caffeine的load put 和invalidate操作都是原子的,這個意思是這3個操作是互斥的巡通,load和put是不能同時執(zhí)行的赊舶,load和invalidate也是不能同時執(zhí)行的。
先load再invalidate摆出,invalidate操作是要等load操作執(zhí)行完的掖举。如果load操作執(zhí)行比較慢快骗,那invalidate操作就要等很久了娜庇。
這樣做有什么好處呢塔次,可以保證結(jié)果完全符合預期。
這種方式和guava是不同的名秀,guava是不阻塞的励负。
先load再invalidate,invalidate操作是馬上執(zhí)行完的匕得,不需要等待load這種耗時操作執(zhí)行完继榆。這個其實不合預期的巾表,根本達不到invalidate的效果了。
先load再invalidate略吨,本意是要讓當前的load操作失效集币,但是load操作時間比較長,load操作結(jié)束是在invalidate之后了翠忠,失效不了這吃load操作鞠苟。
說概念可能比較抽象,我們來舉個例子:
public static void main(String[] args) throws Exception {
final AtomicInteger atomicInteger = new AtomicInteger();
final LoadingCache<String, String> cache = CacheBuilder.newBuilder().maximumSize(500)
.build(new CacheLoader<String, String>() {
@Override
public String load(String s) throws Exception {
Thread.sleep(1000);
return atomicInteger.incrementAndGet() + "";
}
});
cache.get("test");
cache.invalidate("test");
new Thread() {
@Override
public void run() {
try {
String value = cache.get("test");
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
long start = System.currentTimeMillis();
cache.invalidate("test");
System.out.println("use ms:" + (System.currentTimeMillis() - start));
}
}.start();
Thread.sleep(1200);
System.out.println("========" + cache.asMap());
System.out.println("========" + cache.get("test"));
}
結(jié)果是:
use ms:0
========{test=2}
========2
其實我們期望的結(jié)果是3的秽之,不能滿足我們的期望当娱。
再看看caffeine,這個時候原子性就的好處就得到體現(xiàn)了考榨。
public static void main(String[] args) throws Exception {
AtomicInteger atomicInteger=new AtomicInteger();
LoadingCache<String, String> cache = Caffeine.newBuilder().maximumSize(3).build(key -> {
Thread.sleep(1000);
return atomicInteger.incrementAndGet()+"";
});
cache.get("test");
cache.invalidate("test");
new Thread() {
@Override
public void run() {
cache.get("test");
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
long start = System.currentTimeMillis();
cache.invalidate("test");
System.out.println("use ms:"+(System.currentTimeMillis() - start));
}
}.start();
Thread.sleep(1200);
System.out.println("========" + cache.asMap());
System.out.println("========" + cache.get("test"));
}
結(jié)果是:
use ms:802
========{}
========3
這個就是我們想要的結(jié)果了跨细,雖然invalidate阻塞了一段時間。
caffeine實現(xiàn)原理
其實原理很簡單河质,caffeine的存儲就是ConcurrentHashMap冀惭,利用了ConcurrentHashMap自己的node節(jié)點鎖。
invalidate操作對應的就是remove方法
image.png
可以看到remove是加鎖的
而load方法對應的是compute方法
image.png
remappingFunction.apply 這里對應的就是我們具體的load的方法內(nèi)容