当我们在run方法中编写类似yield,sleep之类的东西时,我认为一个线程只放弃了它的统治(控制?)。我希望看到的以下代码的输出类似于:
#1(5), #1(4), #1(3), #1(2), #1(1), #2(5), #2(4), #2(3), #2(2), #2(1), #3(5), #3(4), #3(3), #3(2), #3(1), #4(5), #4(4), #4(3), #4(2), #4(1), #5(5), #5(4), #5(3), #5(2), #5(1)
然而,事实证明所有线程都在同一时间运行。
输出:
#4(5), #2(5), #1(5), #1(4), #1(3), #1(2), #1(1), #3(5), #5(5), #3(4), #2(4), #2(
3), #4(4), #2(2), #3(3), #3(2), #5(4), #3(1), #2(1), #4(3), #4(2), #4(1), #5(3),
#5(2), #5(1)
我很困惑。
public class SimpleThread extends Thread {
private int countDown = 5;
private static int threadCount = 0;
public SimpleThread() {
// Store the thread name:
super(Integer.toString(++threadCount));
start();
}
public String toString() {
return "#" + getName() + "(" + countDown + "), ";
}
public void run() {
while(true) {
System.out.print(this);
if(--countDown == 0)
return;
}
}
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SimpleThread();
}
}
答案 0 :(得分:1)
当我们在run方法中编写类似yield,sleep等内容时,我认为一个线程只放弃了它的控制权(控制?)。
不,完全没有。线程并行运行,每个线程与所有其他线程并发执行。当您从多个线程同时打印到System.out
时,通常会出现乱码输出。
自操作系统使用协作式多任务处理的Windows 3.x天以来,线程或进程无需明确控制权。 UNIX操作系统使用抢先式多任务处理,Windows 95以后的每个版本的Windows也是如此。抢先式多任务处理意味着操作系统可以在任何时候挂起线程,例如当它用完时间片时。
让线程并行运行使程序能够利用当今常见的多核架构。如果一次只能运行一个线程,那么拥有多个CPU就没有任何好处。
答案 1 :(得分:1)
根据规范,不保证线程执行顺序。因此,你不能指望在第二次启动之前完成启动的线程。
根据Kathy Sierra oca / ocp java se 7书(OCA / OCP Java SE 7程序员I&amp; II学习指南):
线程调度程序是JVM的一部分(尽管大多数JVM映射Java线程) 直接到底层操作系统上的本机线程,决定应该使用哪个线程 在任何给定时刻运行,并且还使线程退出运行状态。假设一个 单处理器机器,一次只能运行一个线程。只有一个堆栈 可以一次执行。它是线程调度程序决定哪个 所有符合条件的线程 - 实际上都会运行。当我们说合格时,我们真的 意味着处于可运行状态。 调度程序可以选择处于可运行状态的任何线程作为一个和 只运行线程。如果线程未处于可运行状态,则无法选择它 当前正在运行的线程。正因为如此,我们清楚地知道这里保证的程度如何: 无法保证选择运行可运行线程的顺序。 虽然队列行为是典型的,但不能保证。队列行为意味着 当一个线程完成其“转弯”时,它会移动到该线的末尾 可运行的池并等待它最终到达线的前面,它可以 再次被选中。实际上,我们将其称为可运行的池,而不是可运行的队列 有助于强化这样一个事实:线程并没有按照一定的保证顺序排列
答案 2 :(得分:0)
线程的运行方式主要取决于底层操作系统和硬件。操作系统决定您的线程何时执行以及执行顺序。
例如,如果您的计算机上有多个核心,操作系统可能会尝试同时运行您的线程(同时)。
即使您只有一个核心,操作系统也很可能会尝试公平,并为所有线程提供一些时间来执行,因为它们具有相同的优先级。