问题
当有多个线程运行时,由线程调度器决定哪些线程将会运行,分配CPU时间片。但是,在大多数系统采用的调度策略都是不太相同的,因此,任何依赖于线程调度器来达到程序性能和正确性的并发程序都是不安全和不可移植的。那么,在编写可移植的,健壮性强的并发程序有哪些好的方法?
答案
- 最好的方式是,保证可运行的线程尽可能少,或不明显高于处理器的数量。如果,可运行的线程足够少,对线程调度器而言就不需要“纠结”为哪个线程分配时间片,只需要让多核处理器处理这些线程就好了。从侧面来说,就降低了对线程调度器的调度策略的依赖。那么,保证尽可能少的线程数唯一的方法就是,让每个线程都做有意义任务,从整体而言,就会降低总线程的个数;
- 当程序不正确的时候,是因为线程无法获得足够的时间片的话,不要企图使用Thread.yield的方式,让其他线程让出时间片,来满足自身的需求。这是因为,不同的JVM上对Thread.yield语义的是不相同的,这样就失去了可移值性。另外,在测试期间,使用Thread.yield人为地来增加线程并发性,应该由Thread.sleep(1)来代替Thread.yield;
- 千万不要企图通过调整线程优先级来达到程序的正确性,线程的优先级是最不可移植的特性。
结论
千万不能让程序依赖线程调度器,这样会失去健壮性和可移植性。而Thread.yield和线程优先级这些特性,是最不具有可移植性,程序中不应该使用它们。