第84项:不要依赖于线程调度器

  当有多个线程可以运行时,由线程调度器(therad scheduler)决定哪些线程将会运行,以及运行多长实践。任何一个合理的操作系统在做出这样的决定时,都会努力做到公正,但是所采用的策略却大相径庭。因此,编写良好的程序不应该依赖于这种策略的细节。任何依赖于线程调度器来达到正确性或者性能要求的程序,很有可能都是不可移植的

  编写健壮,响应迅速的可移植程序的最佳方法是确保可运行线程的平均数量不会明显大于处理器数量。这使得线程调度程序几乎没有选择:它只是运行可运行的线程,直到它们不再可运行为止。即使在完全不同的线程调度策略下,程序的行为也不会有太大变化。请注意,可运行线程的数量与线程总数不同,后者可能要高得多。等待的线程是不可运行的。

  保持可运行线程数量尽可能少的主要方法是,让每个线程做些有意义的工作,然后等待更多有意义的工作。如果线程没有在做有意义的工作,就不应该运行 。根据Executor Framework(第80项),这意味着适当地规定了线程池的大小[Goetz06, 8.2],并且使任务保持任务简短但不会太短【尽量让执行任务的时间短一点,但不能太短】,否则调度开销会影响到性能。

  线程不应该一直处于*忙-等(busy-wait)*状态,即反复地检查一个共享对象,等待它的状态发生改变。除了使程序易受到调度器的变化影响之外,忙-等这种做法大大增加了处理器的负担,减少了其他进程可以完成的有用的工作量。作为一个极端的反面例子,考虑下面这个CountDownLatch的不正当的重新实现:

// Awful CountDownLatch implementation - busy-waits incessantly!
public class SlowCountDownLatch {
    private int count;
    public SlowCountDownLatch(int count) {
        if (count < 0)
            throw new IllegalArgumentException(count + " < 0");
        this.count = count;
    }
    public void await() {
        while (true) {
            synchronized(this) {
                if (count == 0)
                    return;
            }
        }
    }
    public synchronized void countDown() {
        if (count != 0)
            count--;
    }
}

  在我的机器上,当1000个线程在锁存器上等待时,SlowCountDownLatch比Java的CountDownLatch慢了大约十倍。虽然这个例子看起来有点牵强,但是系统中有一个或者多个线程处于不必要的可运行状态,这种现象并不少见。性能和可移植性可能会受到影响。

  如果某一个程序不能工作,是因为某些线程无法像其他线程那样获得足够的CPU实践,那么,尽量不要试图通过调用Thread.yield来“修复”该程序 。你可能好不容易成功地让程序能够工作,但这样得到的程序仍然是不可移植的。同一个yield调用在一个JVM实现上能提高性能,而在另一个JVM实现上却有可能会更差,在第三个JVM实现上则可能没有影响。Thread.yield没有可测试的语义(testable semantics) 。更好的解决办法是重新构造应用程序,以减少可并发运行的线程数量。

  有一种相关的方法是调整线程的优先级(thread priorities),同样有类似的警告。线程优先级是Java平台上最不可移植的特征了 。通过调整某些线程的优先级来改善应用程序的响应能力,这样做并非不合理,却是不必要的,也是不可移植的。通过调整线程的优先级来解决严重的活性问题是不合理的。在你找到并修正底层的真正原因之前,这个问题可能会再次出现。

  总之,不要让应用程序的正确性依赖于线程调度器。由此产生的程序既不健壮,也不具有可移植性。作为推论,不要依赖Thread.yield或线程优先级。这些措施仅仅是对调度器做些暗示。线程优先级可以用来提高一个已经能正常工作的程序的服务质量,但永远不应该用来“修复”一个原本就不能工作的程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值