nl101531
V2EX  ›  Java

关于 Java 线程池的一些疑问

  •  1
     
  •   nl101531 ·
    mrdear · Aug 8, 2018 · 4855 views
  •   You need to sign in to view this topic
    This topic created in 2922 days ago, the information mentioned may be changed or developed.

    在《 Java 并发编程艺术》书中有这样一段话

    多线程竞争锁时会引起上下文切换,多余多核处理数据时可以将数据的 ID 按照 Hash 算法取模分段,不同的线程处理不同段的数据。

    关于这个我以线程池为例,可以理解为使用一个大的线程池不如使用多个小的线程池,将任务通过 hash 算法分散到不同的线程池中,线程池的 Channel 是阻塞队列实现,高并发抢任务会造成线程阻塞,导致上下文切换,因此这种分散的方法降低单个线程池抢任务的并发量。

    这样理解有问题吗?这种做法目前没怎么见过,是真的有效果吗?

    Supplement 1  ·  Aug 8, 2018
    写了测试,假设 qps1000,30 个线程能够保证每个处理在 15ms 以内。

    分成 3 个线程池,每个之中有 10 个线程,那么处理会相当慢,竞争很激烈。因此结论不正确。
    18 replies    2018-11-07 17:36:23 +08:00
    vela
        1
    vela  
       Aug 8, 2018
    如果任务的耗时方差比较大,有个别耗时较长,可能会造成部分线程池饥饿。
    简单就这样的代码,但是更多是为了解决按照特定数据进行串行化的……
    Map<Integer, Executor> executorPool;
    void init() {
    executorPool = IntStream.range(0, 10).boxed().collect(collectingAndThen(toMap(identity(), it -> Executors.newXxxx(..))), Collections::unmodifiableMap);
    }

    void foo(SomePojo pojo) {
    executorPool.get(pojo.getSomeField().hashCode() % executorPool.size()).execute(() -> {
    // do something...
    });
    }
    ooToo
        2
    ooToo  
       Aug 8, 2018 via iPhone
    有问题,竞争锁的是线程和线程,不是线程池和池,而且需要同步的才需要竞争锁。CPU 核心就那么多
    nl101531
        3
    nl101531  
    OP
       Aug 8, 2018
    @ooToo 在一个大的线程池里面是那么多线程竞争一个阻塞队列上的锁,而分散开来的话就有了多个锁,每个线程池锁竞争的锁对象是不一样的了。
    szq8014
        4
    szq8014  
       Aug 8, 2018   ❤️ 2
    多个小的线程池不还是用锁来同步吗?这句话的重点应该是 “多线程竞争 [锁] 时会引起上下文切换”,所以最好还是不要把数据上锁,不上锁就需要提前把数据分给每个线程,每个线程一亩三分地自己搞自己的。
    hash 取模后不就做到每个线程不需要锁就可以保证数据安全了么~
    nl101531
        5
    nl101531  
    OP
       Aug 8, 2018
    @szq8014 大佬这分析有道理,貌似是我理解有问题,作者原意应该只是表达可以用这种做法实现无锁。
    D3EP
        6
    D3EP  
       Aug 8, 2018
    @boywang004 偶见天舟 哈哈
    sagaxu
        7
    sagaxu  
       Aug 8, 2018 via Android
    如果多个小线程池优于单个大线程池,线程池内部实现的时候做个分段不就好了?
    ioth
        8
    ioth  
       Aug 8, 2018
    java 还有效率?指针都不敢有。线程什么的,交给 c 和 c++ 吧。
    yidinghe
        9
    yidinghe  
    PRO
       Aug 8, 2018 via Android
    总的来说,有锁在那里,你怎么摆弄线程池没什么区别的
    WildCat
        10
    WildCat  
       Aug 8, 2018
    @ioth 惊了。
    iFlicker
        11
    iFlicker  
       Aug 8, 2018
    @ioth 钓鱼么。。。
    AllenTsui
        12
    AllenTsui  
       Aug 8, 2018
    @ioth PHP 全宇宙第一 <(* ̄ー ̄)ゞ~
    ioth
        13
    ioth  
       Aug 9, 2018
    @AllenTsui 没错,就是一堆$看了脑袋大,是除了 vb 之外 sb 第 2 的语言。
    ioth
        14
    ioth  
       Aug 9, 2018
    @WildCat 本来就是做个小电器的接口语言设计,能不垃圾么?还讲 java 的艺术,那 foxpro 还讲优雅?
    所以后来安卓这种山寨货也就用 java 了。
    vela
        15
    vela  
       Aug 9, 2018
    @D3EP =__=,我难道应该再换个 id 才能不被认出来么。
    wocanmei
        16
    wocanmei  
       Aug 21, 2018   ❤️ 1
    没有看过 Java 并发编程艺术,但看起来这里说的应该是锁分段而不是线程池,比如

    ```java
    public void synchronizeOneLock(int uid) {
    synchronized (this) {

    // ...
    }
    }

    private final Object[] locks;

    public void synchronizeMultiLock(int uid) {
    synchronized (locks[uid % locks.length]) {

    // ...
    }
    }
    ```

    假设用户可以用 uid 表示,synchronizeOneLock 会将所有用户在 this 这一个锁上同步,而 synchronizeMultiLock 则会根据 uid 散列到多个锁上,不同的数据在不同的锁上进行同步,避免了不必要的锁竞争
    nl101531
        17
    nl101531  
    OP
       Aug 21, 2018
    @wocanmei 感谢,是应该这样理解
    409474917
        18
    409474917  
       Nov 7, 2018
    @ioth 你这个喷子呀,有本事不要用淘宝,淘宝 86%的系统后台都是 java 写的,你也不要用安卓手机,你的家人也不要用安卓手机。看你的这些发言,实际中你应该是个没房没车的屌丝,每个月拿着几千块钱的工资。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2701 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 50ms · UTC 04:56 · PVG 12:56 · LAX 21:56 · JFK 00:56
    ♥ Do have faith in what you're doing.