V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
mmdsun
V2EX  ›  问与答

请教一 Java 多线程设计的问题

  •  
  •   mmdsun · 2019-03-18 10:32:19 +08:00 via Android · 1819 次点击
    这是一个创建于 2113 天前的主题,其中的信息可能已经有所发展或是发生改变。

    多个线程,同时分页查询数据库每次 1000 条,然后 java 程序过滤这一千条数据,将满足条件的数据被 add 一个新集合里面,这个集合每 100 条输出一次 Excel。

    我隐约记得 java 的某些集合的 add 操作不是线程安全的,有些并发容器 size 判断会不准确。还得满足条件 100 条输出一次(此时 add 操作应该会暂停),不足 100 条等待下一次 1000 条查询。

    请问这种需求应该如何设计多线程? java 有否这种生产者模式的 api,类库等。

    12 条回复    2019-03-18 17:39:09 +08:00
    sundae91
        1
    sundae91  
       2019-03-18 11:11:05 +08:00
    CopyOnWriteArrayList?
    kiddult
        2
    kiddult  
       2019-03-18 11:15:44 +08:00
    生产者+消费者,消费者单线程执行
    momocraft
        3
    momocraft  
       2019-03-18 11:19:37 +08:00
    java.util.concurrent 有线程安全的容器
    rockyou12
        4
    rockyou12  
       2019-03-18 11:23:14 +08:00   ❤️ 1
    你查数据库量级多少,查询条件复杂不?如果不复杂量,量级就万来条你单线程不分页可能还快些。

    如果你 Java 里过滤条件比较耗时,直接用 parallelStream().filter().sequential() 这样结果也是保证顺序的
    peyppicp
        5
    peyppicp  
       2019-03-18 11:26:41 +08:00   ❤️ 1
    首先 new 一个 Object 作为互斥量,创建一个 LinkedList 或者什么,两个方法一个写入数据,一个读取数据,针对这个 Object 上锁。取数据得时候 for 循环到 100 条之后退出循环即可

    对于数据库查询 1000 条数据,然后过滤的需求,使用线程池搞定,向线程池提交 Future,然后在 Future 里对数据进行处理,然后调用写入数据的方法写入数据

    如果想准确得知 list 的 size,就直接包装一层,先拿锁,再调用 list.size 方法。就我看来读取数据库时间应该远超锁切换时间,应该是值得的
    不知道我讲清楚了没有。。
    peyppicp
        6
    peyppicp  
       2019-03-18 11:34:12 +08:00
    其实性能不重要的场景 用不用并发容器都无所谓,自己用 sync 关键字包一层就完事了
    mmdsun
        7
    mmdsun  
    OP
       2019-03-18 12:09:58 +08:00 via Android
    @sundae91 @kiddult @momocraft @rockyou12 @peyppicp

    谢谢大家,目前打算使用加锁的方案。数据库查询还是比较耗时的操作。

    看了几个 java 并发容器的 api 感觉场景不适合,比如 CopyOnWriteArrayList 用在读多写少的场景会更好。另外发现 java 的一些阻塞队列 api 应该可以做到,但由于不太熟悉 api 害怕会有什么坑。暂时打算加锁解决。
    Lattez
        8
    Lattez  
       2019-03-18 12:20:48 +08:00
    看了一眼之前写的,也是分页 1000 查的数据写 Excel,用的是 CopyOnWriteArrayList,当然这玩意本身底层实现就是 add 的时候上锁拷贝的
    Weixiao0725
        9
    Weixiao0725  
       2019-03-18 12:25:29 +08:00
    这个用条件变量可以实现吧
    choice4
        10
    choice4  
       2019-03-18 14:15:16 +08:00 via Android
    都说生产者消费者了,阻塞队列不行吗?有个什么 blockinglinkedqueue?
    choice4
        11
    choice4  
       2019-03-18 14:20:27 +08:00 via Android
    #10 LinkedBlockingQueue
    mccreefei
        12
    mccreefei  
       2019-03-18 17:39:09 +08:00
    每个线程处理 1000 条,每过滤出 100 条有效数据封装一下塞到阻塞队列里,多余的数据加锁暂时存放到 list 中,消费者线程从阻塞队列里 100 条、100 条地拿数据写 excel,利用 countDownLatch,最后一个生产者线程处理那个 list ( list 中每 100 条塞阻塞队列)。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2851 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:07 · PVG 22:07 · LAX 06:07 · JFK 09:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.