总是套路留人心, JAVA提供的套路: LinkedHashMap实现LRU缓存; InvocationHandler实现动态代理; fork/join实现窃取算法

时间:2022-12-24 00:14:41

1. LinkedHashMap实现LRU缓存

LRU缓存核心是根据访问顺序排序, 自动移除队尾缓存, LinkedHashMap已经实现了这些要求:

public LRUCache<K, V> extends LinkedHashMap<K, V> {
private int cacheSize; public LRUCache(int cacheSize){
super(16, 0.75, true); // key1: true表示使用访问排序, 默认false表示插入排序
}
@Override
protected boolean removeEldestEntry(Map.Entry<k, V> eldest){
return size() >= cacheSize; //key2: 每次调用add后, 底层都会调用这个方法判断是否执行移除队尾元素, 通过重写这个方法来控制移除时机
}
}

2.InvocationHandler实现动态代理

手工为每一个类实现一个代理类称为静态代理, 缺点是即使代理的操作是一样的, 仍然要为每个类实现一个代理类, 代理操作代码不能复用

//1.实现代理类
public class MyInvocationHandler implements InvocationHandler {
private Object target; MyInvocationHandler() {
super();
} MyInvocationHandler(Object target) {
super();
this.target = target;
} @Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
if("getName".equals(method.getName())){
System.out.println("++++++before " + method.getName() + "++++++");
Object result = method.invoke(target, args);
System.out.println("++++++after " + method.getName() + "++++++");
return result;
}else{
Object result = method.invoke(target, args);
return result;
}
} //2.获得代理对象
(TargetInterface)Proxy.newProxyInstance(tarInterClass.getClassLoader(), tarInterClass.getInterface(), new MyInvocationHandler(tarObj));

可以看出Proxy.newProxyInstance()获得的是对一个接口的代理, 这也是InvocationHandler动态代理的缺点:只能代理接口中的方法.

想代理类中非implement接口的方法, 可以用第三方Cglib代理实现

3.fork/join实现窃取模式

窃取模式是一种升级版的生产者-消费者模式, 特点是线程在处理完自己的任务队列后, 回去其他线程的任务队列的末尾窃取任务来执行, 以提高效率.

如果自己实现窃取模式:首先要一个线程池来执行任务, 其次要为每一个线程提供一个任务队列, 最后还要实现窃取其他队列的任务的功能. 幸运的是JAVA已经提供了实现.

//1.编写任务类implement
RecursiveAction 不反回结果, 相当于Runnable
RecursiveTask 返回结果, 相当于Callable
//2.获得线程池
ForkJoinPool pool = new ForkJoinPool()
//3.提交任务
pool.execute() 异步执行命令
pool.invoke() 执行命令并直接返回结果
pool.submit() 执行任务并返回一个ForkJoinTask(Future)
//4.子RecusiveAction
fork() //把自身添加到任务执行队列
join() //获得执行结果

在compute()的实现中, 根据条件将任务分成更细的多个RecusiveTask, 就实现了分治法