• 锦
    2019-05-21
    在应用系统中,日志系统一般都是最后关闭的吧,因为它要为其他系统关闭提供写日志服务。所以日志系统关闭时需要把队列中所有日志都消费掉才能关闭。
    可能需要在关闭日志系统时投入一个毒丸,表示没有新的日志写入。线程池在消费到毒丸时知道没有日志写入,将所有的日志刷盘,break循环体。

    作者回复: 👍

    
     56
  • PK時頭髮不亂
    2019-05-21
    极客时间有好多课程, 我觉得王老师的干货是最实际最可用的, 必须要赞一个。

    作者回复: 感谢感谢,有钱难买合适:)

     1
     22
  • 聂旋
    2019-05-23
    安卓的主线程中也是采用消息队列加消息循环方式,来处理用户输入及各种事件。当应用退出时,会发送一个处理对象为null的消息给队列,消息循环遇到这样的消息时就退出了。
     2
     9
  • êwěn
    2019-05-22

    之前遇到过一个生产问题,一个服务启动一段时间后就不停的超时,后面结合线程栈发现很多阻塞在打印日志的地方(我们用的就是log4j2),后面查到机子硬盘问题,io直接100%以上,日志刷盘满导致消费速度慢,队列撑满阻塞了写,这间接说明平衡好生产和消费速度以及适当的队列大小是很有必要。

    作者回复: 能快速定位的问题👍👍

    
     8
  • Asanz
    2019-08-08
    看到很多示例代码都没有关闭线程池的动作,难道局部的线程池就不要关闭吗?

    作者回复: 需要

    
     4
  • 苏籍
    2019-05-22
    您好老师问个最近用到的线程池使用的问题
    我的工程是springboot的,在unitTest里(@SpringBootTest) 里调用了一个service A(通过@Autowired的)中的方法,A中启用了一个线程池,执行的任务 是往数据库里插入数据。但是总抛出数据源已经被关闭的异常,我理解的是在单测主线程已经结束,所以关闭了数据源这些清理工作,而此时线程池的线程还
    没结束,这个时候去调用数据源是null 的,不知道这么理解对不对,另外这个test主线程结束,为啥线程池的线程还没结束(通过打断点看到的)。这个怎么理解,求教
    展开

    作者回复: 只有守护线程才会自动结束,线程池的线程不是守护线程

    
     4
  • 晓杰
    2019-05-21
    35讲说到优雅地终止线程,首先需要线程状态转换为runnable状态(在终止刷盘的方法中调用Thread.interrupt()方法)
        然后可以通过设置标志位来让线程优雅终止,具体有两种方式:
        1、通过判断线程的中断状态Thread.currentThread.isInterrupted()
        2、设置自己的线程终止标志位,该标志位volatile修饰的共享变量。(这种方式需要在终止刷盘的方法中修改该共享变量的值)
    
     3
  • ack
    2019-05-21
    public class Logger {
        ...
        
        volatile boolean stop;

        // 启动写日志线程
        void start() throws IOException {
            ...
            this.es.execute(() -> {
                try {
                    // 未刷盘日志数量
                    int curIdx = 0;
                    long preFT = System.currentTimeMillis();
                    while (!stop) {
                           ...
                    }
                } catch (InterruptedException e) {
                    // 重新设置线程中断状态
                    Thread.currentThread().interrupt();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    ...
                }
            });
        }
        ...
        void stop(){
            stop = true;
            es.shutdown();
        }
    }
    展开
    
     3
  • berthav_ss
    2019-06-11
    宝令老师,如何优雅的停止线程池中某一组线程呢?例如我在线程a中启动了1-10线程,线程b中启动了2-30线程,如何优雅停止1-10线程呢

    作者回复: 可以考虑一下毒丸的方式

    
     2
  • 曾轼麟
    2019-05-23
    补充一下上面的留言,先通过创建的钩子去创建一个毒丸,然后释放资源
    
     2
  • 曾轼麟
    2019-05-23
    使用Runtime提供的钩子,然后在关闭前,先让内部任务执行完毕,再释放资源
    
     2
  • 泛岁月的涟漪
    2019-05-21
    1、使用线程池的shutdown或者shutdownNow关闭线程池
    2、while循环条件设置为一个volatile boolean变量
    3、可以使用interrupt,但是线程是线程池管理的,没有消费者线程的引用中断不了
    
     2
  • null
    2019-07-26
    private BlockingQueue<X> bq = new LinkedBlockingQueue<>(1000);

    // 从任务队列中获取批量任务
    List<X> pollTasks() throws InterruptedException{
      List<X> ts=new LinkedList<>();

      X t = bq.take();
      while (t != null) {
        ts.add(t);
        t = bq.poll();
      }

      return ts;
    }

    -----

    需求背景:(一个线程往 bq 写数据,三个线程从 bq 读数据)
    1. 线程 A 从数据库批量读取数据,每次读 1000 条记录,然后在 for 循环内写入队列 bq.put(x)。
    2. 线程 B、线程 C、线程 D 调用 pollTasks() 方法获取数据列表,然后将数据列表做为参数,调用 Y 接口获取一批数据,最后进行业务运算。

    -----

    跑 demo 时发现 pollTasks() 方法有两个地方需要注意一下(一是:获取的列表数量不均,二是:退化成单元素列表):
    1. 线程 B、C、D 调用 pollTasks() 获得的列表,数据量不均匀,例如线程 B 只读取到 10+ 个元素,而线程 C 却读取了 1000+ 个元素。
    2. 如果我上游写入队列 bq 速度较慢(通过一些复杂的运算再写入 bq),这时下游通过 pollTasks() 获取的列表,几乎都是只有一个元素的列表。


    列表数据不均,可以增加返回列表的上限,或者增加超时机制。

    退化成单元素列表:
    1. pollTasks() 的调用方主动等待片刻,再获取数据。
    2. 修改 pollTasks() 的实现,返回列表的前提条件是:列表的 size 必须 batchSizeLimit 下限,否则等待超时 System.currentTimeMillis()-startMillis>1000。
    展开
    
     1
  • 张三
    2019-05-22
    还是不太懂,线程池的实现是有两种模式吗? Worker Thread 和 生产者-消费者 模式 ?
    
     1
  • 佑儿
    2019-05-21
    声明一个volatie变量用于表示线程结束,为true时,退出循环

    作者回复: 队列中的任务就丢了

    
     1
  • 密码123456
    2019-05-21
    设置一个volitle 。这里中断设置不了,没有引用。我觉得一个volite关键字够了。之前说happens before的时候说,volit写,优于volit读,应该立刻可见。还要问下老师,这么理解可以吗?中断是不是一定必须的?

    作者回复: 可见,中断要看场景

    
     1
  • feihui
    2020-01-24
    日志的那个程序中“LogMsg log = bq.poll( 5, TimeUnit.SECONDS);” 其中的 5 是不是应该是动态计算为 System.currentTimeMillis()-preFT,不然会出现旧数据 10 秒后才保存
    
    
  • 放个屁臭到了自己
    2019-11-25
    如果使用轻量级线程,就没有必要平衡生产者和消费者的速度差异了,因为轻量级线程本身就是廉价的,

    为什么廉价就不需要平衡?

    作者回复: 廉价意味着可以轻松创建很多,线程是不能创建很多的。

     1
    
  • Joker
    2019-11-08
    如果没有队列的话:就会,一个生产线程就需要一个消费线程来相互跟进,所以这个就但是消费的赶不上生产的速度,就导致了两个问题:1.等待,2.多余线程创建。
    
    
  • 生活用来品
    2019-09-18
    请问一下高并发场景,四个人拼一个团,怎么拼?
    1.db里记录拼团人数,如果小于4则直接update到拼团用户表,否则创建新的拼团id,新的记录。
    2.高并发场景,怎么保证读写db的一致性?redis和db双写?
    3.期待老师高见

    作者回复: 高并发下,我觉得主要是做好限流和缓存,保护好瓶颈资源数据库,限流和缓存的方案要看流量大小和系统架构

    
    
我们在线,来聊聊吧