高并发实战2---手写计算器缓存

对于初级版本(高并发实战1)的提升一级优化

  • 不直接缓存计算结果,而是缓存计算任务(future可以阻塞线程),当没有从缓存中读到正在执行计算的任务的时候,直接阻塞等待正在执行的任务计算的结果,然后读取缓存,减少重复的计算

顶层类依然不变

package com.ljq.mydemo.thread.compute;

/**
 *
 * 定义计算的接口
 *包含一个 用户计算的函数式接口
 * @author gino
 * 2021-11-17
 */
public interface Computable<A,V> {

    /**
     * 定义函数式接口
     * @param ags
     * @return
     * @throws InterruptedException
     */
    public V compute(A ags) throws InterruptedException;
}

#采用Futuer的方式更好的减少重复计算的次数

package com.ljq.mydemo.thread.compute;

import java.util.Objects;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 中级demo
 * 解决初级demo  的问题,
 * 改成每次使用Future来判断是否有线程正在计算
 * 如果有线程正在执行计算于当前线程相同的计算  则直接阻塞等待 上个线程的结果直接,等上一个线程将结果计算完毕  直接从cache中拿
 *
 *
 *
 *
 * <p>
 * 实现一个带有 “记忆”  功能计算接口
 * 该接口是使用于  多线程 ,计算费时长  的任务
 * <p>
 * A  参与计算的参数
 * V  参与计算的结果
 *
 * @author gino
 * 2021-11-17
 */
public class MemoryCompute002<A, V> implements Computable<A, V> {
    /**
     * 为了保证并发线程安全,以及线程安全的效率
     * 所用采用ConcurrentHashMap  而不是采用synchronized
     * 因为ConcurrentHashMap 采用的是分段锁, 而synchronized 会锁住整个方法
     * <p>
     * 缓存计算参数以及计算接口
     */
    private final ConcurrentHashMap<A, Future<V>> cache = new ConcurrentHashMap();

    /**
     * 定义计算的计算器,计算器通过构造函数传递
     */
    private final Computable<A, V> computable;


    public MemoryCompute002(Computable<A, V> computable) {
        this.computable = computable;
    }

    @Override
    public V compute(A ags) throws InterruptedException {
        V result = null;
        Random random=new Random();
        int i = random.nextInt(5);
        Thread.sleep(i*1000);
        System.out.println(Thread.currentThread().getId()+" starting ");
        //依旧是先取缓存  ,不过取到的不是V  而是Future
        Future<V> f = cache.get(ags);
        if (Objects.isNull(f)) {
            //判断是否有任务正在执行于当前一样的计算,没有则执行计算
            Callable exc = new Callable() {
                @Override
                public Object call() throws Exception {
                    return computable.compute(ags);
                }
            };
            FutureTask<V> ft = new FutureTask<>(exc);
            f = ft;
            //将计算任务加入缓存(如果不存在才加入缓存)
            cache.putIfAbsent(ags, ft);
            //开始计算
            System.out.println(Thread.currentThread().getName()+": get cache fail ,is computing.......");
            ft.run();

        }
        try {
            result = f.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return result;
    }
}

测试

package com.ljq.mydemo.thread.compute;

import java.math.BigInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author gino
 * 2021-11-17
 */
public class ComputeTest002 {


    public static void main(String[] args) throws InterruptedException {
        //实例具体的计算方法
        ExampleCompute compute=new ExampleCompute();
        //实例化到计算的容器
        MemoryCompute002<String, BigInteger> memoryCompute=new MemoryCompute002(compute);

        //单线程
     //   OneThread(memoryCompute);

        //多线程
        MoreThread(memoryCompute);
    }

    /**
     * 单线程
     * @param memoryCompute
     * @throws InterruptedException
     */
    public static void OneThread( MemoryCompute002<String, BigInteger> memoryCompute) throws InterruptedException {
        for (int i = 0; i <5 ; i++) {
            System.out.println("create randomNumber: "+6);
            memoryCompute.compute(String.valueOf(6));
        }

    }

    /**
     * 多线程
     * @param memoryCompute
     * @throws InterruptedException
     */
    public static void MoreThread( MemoryCompute002<String, BigInteger> memoryCompute){
        //创建带缓存的线程池
        ExecutorService services = new ThreadPoolExecutor(2, 5,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        //模拟多线程访问
        for (int i = 0; i <5 ; i++) {

            services.execute(()->{
                System.out.println("compute args : "+6);
                try {
                    BigInteger compute = memoryCompute.compute(String.valueOf(6));
                    System.out.println(Thread.currentThread().getId()+" get result :"+compute);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        //关闭数据库连接池
        services.shutdown();
    }

}

结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值