请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

main函数里用lambda表达式创建任务,会输出3次“从FutureTask调用了计算函数”?

package imoocCache;

import imoocCache.computable.Computable;
import imoocCache.computable.ExpensiveFunction;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * ImoocCache2缺点:如果在计算完成前,另一个要求计算相同值的请求到来,会导致计算两遍,这和缓存想避免多次计算的初衷恰恰相反
 * 改进:利用Future避免重复计算
 */
public class ImoocCache3<A,V> implements Computable<A,V> {

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

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

    @Override
    public V compute(A arg) throws Exception {
        Future<V> f = cache.get(arg);
        if (f == null) {
            Callable<V> callable = new Callable<V>() {
                @Override
                public V call() throws Exception {
                    return c.compute(arg);
                }
            };
            FutureTask<V> ft = new FutureTask<>(callable);
            f = ft;
            // 任务开始计算之前先存入缓存,这样其他计算相同任务的线程就可以直接从缓存中读取该任务的执行结果
            // 如果该任务还没执行完成,则其他线程调用Future.get方法时会被阻塞
            cache.put(arg, ft);
            System.out.println("从FutureTask调用了计算函数");
            ft.run();
        }
        return f.get();  // get方法在任务计算过程中会被阻塞,直到任务完成
    }

    public static void main(String[] args) throws Exception {
        ImoocCache3<String, Integer> expensiveComputer = new ImoocCache3<>(
                new ExpensiveFunction());
        new Thread(() -> {
            try {
                Integer result = expensiveComputer.compute("666");
                System.out.println("第一次的计算结果:"+result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                Integer result = expensiveComputer.compute("666");
                System.out.println("第三次的计算结果:"+result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()-> {
            try {
                Integer result = expensiveComputer.compute("667");
                System.out.println("第二次的计算结果:"+result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }
}

正在回答 回答被采纳积分+3

1回答

提问者 小曼巴0 2021-12-29 14:58:18

使用lambda表达式时,线程2在线程1执行cache.put之前就已经进入了if语句内部,而创建Runnable对象则不会?

难道是因为创建Runnable需要消耗一定的时间,在这段时间内线程1已经执行完cache.put语句?而使用lambda表达式不用创建Runnable对象,线程1和线程2几乎同时执行?

下载视频          
0 回复 有任何疑惑可以回复我~
  • 悟空 #1
    这个我试过了,不是lambda表达式的问题,如果用Runnable对象同样可能有重复计算问题,因为大家是同一时间去做的compute,而且667用不上666的缓存。你试一下在第3次计算前,sleep一下,就会发现,不会重复计算了。
    回复 有任何疑惑可以回复我~ 2021-12-30 10:41:35
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信