静态代理设计模式

87 阅读1分钟
package com.justalk.javademo.thread;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Cache {

    public interface Computable<A, V> {
        V compute(A a) throws InterruptedException;
    }

    public class ExpensiveFunction implements Computable<String, BigInteger> {

        @Override
        public BigInteger compute(String o) throws InterruptedException {
            return new BigInteger(o);
        }
    }

    /**
     * Memoizer1因为synchronized而变成串行执行,效率低效
     *
     * @param <A>
     * @param <V>
     */
    public class Memoizer1<A, V> implements Computable<A, V> {

        private final Map<A, V> cache = new HashMap<A, V>();
        private final Computable<A, V> c;

        public Memoizer1(Computable<A, V> c) {
            this.c = c;
        }

        @Override
        public synchronized V compute(A a) throws InterruptedException {
            V v = cache.get(a);
            if (v == null) {
                v = c.compute(a);
                cache.put(a, v);
            }
            return v;
        }
    }

    /**
     * Memoizer2,因为ConcurrentHashMap是分段锁,可能会又有重复计算的情况
     *
     * @param <A>
     * @param <V>
     */
    public class Memoizer2<A, V> implements Computable<A, V> {
        private final Map<A, V> cache = new ConcurrentHashMap<>();
        private final Computable<A, V> c;

        public Memoizer2(Computable<A, V> c) {
            this.c = c;
        }

        @Override
        public V compute(A a) throws InterruptedException {
            V v = cache.get(a);
            if (v == null) {
                v = c.compute(a);
                cache.put(a, v);
            }
            return v;
        }
    }

    public class Memoizer3<A, V> implements Computable<A, V> {

        private final Map<A, Future<V>> cache = new ConcurrentHashMap<>();
        Computable<A, V> c;

        public Memoizer3(Computable<A, V> c) {
            this.c = c;
        }

        @Override
        public V compute(A a) throws InterruptedException {

            while (true) {
                Future<V> f = cache.get(a);
                if (f == null) {
                    Callable<V> callable = new Callable<V>() {
                        @Override
                        public V call() throws Exception {
                            return null;
                        }
                    };
                    FutureTask<V> ft = new FutureTask<>(callable);
                    f = cache.putIfAbsent(a, ft);
                    if (f == null) {
                        f = ft;
                        ft.run();
                    }
                }
                try {
                    return f.get();
                } catch (CancellationException e) {
                    //如果被取消了,那么从缓存中去掉
                    cache.remove(a,f);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //真正用来计算的对象
    private  final Computable<BigInteger,BigInteger[]> c = new Computable<BigInteger, BigInteger[]>() {
        @Override
        public BigInteger[] compute(BigInteger bigInteger) throws InterruptedException {
            return new BigInteger[0];
        }
    };

    //包装计算对象的缓存对象
    private  final Computable<BigInteger,BigInteger[]> cache = new Memoizer3<>(c);

    //通过缓存对象进行对应的计算
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要查询的对象key:");
        int i = scanner.nextInt();
        System.out.println(String.format("您输入的数字是:%d",i));
        System.out.println("计算结果是:");
        Cache cache = new Cache();
        try {
            BigInteger[] compute = cache.cache.compute(BigInteger.valueOf(i));
            System.out.println(Arrays.toString(Arrays.stream(compute).toArray()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}