0%

16.3.1 新建状态和就绪状态

16.3.1 新建状态和就绪状态

什么时候线程处于新建状态

当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象样,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。

什么时候线程处于就绪状态

当线程对象调用了start方法之后,该线程处于就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了。至于该线程何时开始运行,取决于JVM里线程调度器的调度。

永远不要调用线程对象的run方法

启动线程使用start()方法,而不是run()方法!永远不要调用线程对象的run()方法!

  • 调用start()方法来启动线程,系统会把该run()方法当成线程执行体来处理;
  • 如果直接调用线程对象的run()方法,系统把线程对象当成一个普通对象,把run()方法当成一个普通方法,而不是线程执行体,run()方法将立即就会被执行,而且在run()方法返回之前其他线程无法并发执行

程序示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class InvokeRun extends Thread
{
private int i ;
// 重写run方法,run方法的方法体就是线程执行体
public void run()
{
for ( ; i < 100 ; i++ )
{
// 直接调用run方法时,Thread的this.getName返回的是该对象名字,
// 而不是当前线程的名字。
// 使用Thread.currentThread().getName()总是获取当前线程名字
System.out.println(Thread.currentThread().getName()
+ " " + i); // ①
}
}
public static void main(String[] args)
{
for (int i = 0; i < 100; i++)
{
// 调用Thread的currentThread方法获取当前线程
System.out.println(Thread.currentThread().getName()
+ " " + i);
if (i == 20)
{
// 直接调用线程对象的run方法,
// 系统会把线程对象当成普通对象,run方法当成普通方法,
// 所以下面两行代码并不会启动两条线程,而是依次执行两个run方法
new InvokeRun().run();
new InvokeRun().run();
}
}
}
}

运行效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
main 0
main 1
main 2
main 3
......
main 18
main 19
main 20
main 0
main 1
main 2
......
main 44
main 45
main 46
main 47
main 48
main 49
main 0
main 1
main 2
main 3
......
main 47
main 48
main 49

上面程序创建线程对象后直接调用了线程对象的run()方法,程序运行的结果是整个程序只有一个线程:主线程。还有一点需要指出,如果直接调用线程对象的run()方法,则run()方法里不能直接通过getName()方法来获得当前执行线程的名字,而是需要使用Thread.currentThread()方法先获得当前线程,再调用线程对象的getName()方法来获得线程的名字。
通过上面程序不难看出,启动线程的正确方法是调用Thread对象的start()方法,而不是直接调用run()方法,否则就变成单线程程序了

只能对处于新建状态的线程调用start方法

只能对处于新建状态的线程调用start方法,否则将引发IllegalThreadStateException异常。调用了线程的run()方法之后,该线程已经不再处于新建状态,不要再次调用线程对象的start()方法。
调用线程对象的start方法之后,该线程立即进入就绪状态——就绪状态相当于”等待执行”,但该线程并未真正进入运行状态。

如何让子线程立即执行

如果希望调用子线程的start方法后子线程立即开始执行,程序可以使用Thread.sleep(1)来让当前运行的线程(主线程)睡眠1毫秒——1毫秒就够了,因为在这1毫秒内CPU不会空闲,它会去执行另一个处于就绪状态的线程,这样就可以让子线程立即开始执行。

本文重点

  • 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态
  • 当线程对象调用了start方法之后,该线程处于就绪状态,就绪状态相当于”等待执行”状态,此时该线程并未真正进入运行状态。
  • 只能对处于新建状态的线程调用start方法,否则将引发IllegalThreadStateException异常
  • 启动线程的正确方法是调用Thread对象的start()方法,而不是直接调用run()方法,直接调用了线程对象的run()方法,程序运行的结果是整个程序只有一个线程:主线程
  • 如果希望调用子线程的start方法后子线程立即开始执行,则可以让当前运行的线程(主线程)睡眠1毫秒,这种情况针只有一个子线程的情况,个人觉得用处不大.

    原文链接: 16.3.1 新建状态和就绪状态