• 辣么大
    2020-02-03
    思考题:startRepeatedReport()多次调用,会启动多个线程,每个线程都会执行统计和输出工作。
    想了一种简单的实现方式,将runnable做为成员变量,第一次调用startRepeatedReport()时初始化,若多次调用,判空,返回。
      public void startRepeatedReport(long periodInSeconds, long durationInSeconds) {
        if (runnable != null) {
          System.out.println("duplicate calls!");
          return;
        }
        runnable = () -> {
          long durationInMillis = durationInSeconds * 1000;
          long endTimeInMillis = System.currentTimeMillis();
          long startTimeInMillis = endTimeInMillis - durationInMillis;
          doReport(startTimeInMillis, endTimeInMillis);
        };
        executor.scheduleAtFixedRate(runnable, 0, periodInSeconds, TimeUnit.SECONDS);
      }
    代码放在了:https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u40
    展开
    
     3
  • Jxin
    2020-02-03
    先回答问题:
    1.会导致多余线程做多余的统计和展示。因为每次调用都会起一个异步线程输出统计数据到控制台。这样既会带来额外的性能开销,又会导致统计信息不易阅读。

    2.在ConsoleReporter内部维护一个可视字段 started。然后在方法执行时,优先判断该字段是否已经变为true。如果是则不再往下执行。也算是保证该函数的幂等性。

    个人疑问:
    1.怎么做到这样分步展示重构过程的?我现在写,基本一边写就一边重构,停手也就差不多到合适的质量了。刻意要展示重构手法,展示的知识点会有很多疏漏,并无法做到这样一步一步的展示(下意识一步到位,并不知道怎么退到不好的代码结构)。

    2.能理解栏主尽量不依赖任何框架的初衷。但对于java,spring其实才是标准,感觉是不是基于spring框架来写demo还好点? 我现在比较喜欢让代码依赖spring框架来实现,感觉这样会显得优雅一些。栏主怎么看?

    展开
     4
     2
  • undefined
    2020-02-03
    深入浅出,过瘾。
    
     1
  • 小晏子
    2020-02-03
    课后思考:如果 startRepeatedReport()被多次调用,那么会生成多个线程以fixed rate去请求然后输出结果到console上,一方面导致输出结果混乱,另一方面增加了系统的负担。
    要解决该问题有个办法是再重构一下代码,示意如下(未测试),
    ```
    private Future<?> future;
    //避免创建多个线程,也可以放在其他地方,如构造函数里
    private Runnable runnable = new Runnable () {
           @Override
           public void run() {
               ....
            }
    };

    public void startRepeatedReport(long periodInSeconds, long durationInSeconds) {
        future.cancel(true); //每次调用就取消上一次的调用
        future = service.scheduleAtFixedRate(runnable, 0L, periodInSeconds, TimeUnit.SECONDS); //重新开始
    }
    ```
    展开
    
     1
  • 高源
    2020-02-03
    老师39,40课完整源代码可以提供下吗,我准备好好研究学习下
    
     1
  • 守拙
    2020-02-04
    课堂讨论:



    正常情况下,ConsoleReporter 的 startRepeatedReport() 函数只会被调用一次。但是,如果被多次调用,那就会存在问题。具体会有什么问题呢?又该如何解决呢?



    startRepeatedReport()多次调用会导致SingleThreadExecutor排队执行任务. 从性能上, 浪费系统资源, 从需求上, 不符合方法设计的初衷. 解决方案之一是使用免锁容器存储唯一值, 作为任务已开始调度的flag, 在startRepeatedReport()方法判断: 如果任务已开始调度, 则直接return.
    展开
    
    
  • Andy
    2020-02-04
    老师能提供课程代码吗?
    
    
  • javaadu
    2020-02-03
    课堂讨论,使用一个标记flag作为该函数被调用国的标记,并给这个函数加锁,解决并发问题
    
    
  • 平风造雨
    2020-02-03
    调用多次可以通过多线程共享的状态变量来解决,CAS或者加锁进行状态的变更。
    
    
  • Jeff.Smile
    2020-02-03
    沙发,打卡!一路跟进!
    
    
我们在线,来聊聊吧