13.2 线程的创建

在Java语言中,可通过系统提供的编程接口去创建线程。

13.2.1 如何创建线程

创建线程的方法一般有两种。

1.通过Runnable接口的方式创建线程

在Java中,线程是一种对象,但不是所有的对象都可以称为线程,只有实现了Runnable接口的类,才可以称为线程。下面先看看Runnable接口的定义。


public interface Runnable

{

public abstract void run();

}


Runnable接口只有一个抽象方法“run()”,要实现这个接口,只要实现这个抽象方法就可以。只有实现了这个接口的类,才有资格称为线程。创建线程的结构如下:


Thread t=new Thread(runnable对象);


runnable对象是指实现了Runnable接口类的对象。当线程执行时,runnable对象中的“run()”方法会被调用。如果想要运行上面创建的线程,还需要调用一个Thread类的方法。


t.start();


【实例13.1】下面举个有关创建线程的实例。


01 ///创建两个线程,让其交替运行

02 public class threadtest

03 {

04 public static void main(String[]args)

05 {

06 compute c=new compute();

07 compute1 c1=new compute1();

08 Thread t=new Thread(c);

09 Thread t1=new Thread(c1);

10 t.start();

11 t1.start();

12 }

13 }

14 ///这是一个线程类

15 ///这个类主要是用来通过循环语句输出数字

16 class compute implements Runnable

17 {

18 int i=0;

19 public void run()

20 {

21 for(int i=0;i<10;i++)

22 {

23 System.out.println(i);

24 }

25 }

26 }

27 ///这是一个线程类

28 ///这个类主要是用来通过循环语句输出字符串语句

29 class compute1 implements Runnable

30 {

31 public void run()

32 {

33 for(int i=0;i<10;i++)

34 {

35 System.out.println("这个数字是:"+i);

36 }

37 }

38 }


【代码说明】第16~38行创建了两个线程compute和compute1,它们都实现接口Runnable。第6~7行分别创建这两个线程的对象,然后第10~11行开始运行线程。

【运行效果】


0 这个数字是:0

1 这个数字是:1

2 这个数字是:2

3 这个数字是:3

4 这个数字是:4

5 这个数字是:5

6 这个数字是:6

7 这个数字是:7

8 这个数字是:8

9 这个数字是:9


这个程序段中,创建了两个线程,不过读者多次运行后可能结果会有不同。那为什么会输出不同的结果呢?

因为在程序中存在一个执行问题。在Java技术中,线程通常是抢占式的,其不需要时间片的分配。抢占式调度模式指许多线程处于可以运行状态,即等待状态,但实际只有一个线程在运行。该线程一直运行到它终止,或者另一个具有更高优先级变成可运行状态。在后一种情况下,低优先级线程被高优先级线程抢占且获得运行机会。

说明

如果把上面的程序再运行一次,可能结果又不一样了,因为它的抢占方式,在目前这个程序段里是无法控制的。

Java调度器支持不同优先级线程抢占方式,不支持相同优先级线程时间片轮换。但如果所在的系统支持时间片轮换,它也会支持。如何才能输出自己想要的结果?后面会学习如何解决这个问题。

2.通过继承Thread类来创建线程

其实Thread类本身也实现了Runnable接口,所以只要让一个类能够继承Thread类,并覆盖“run()”方法,也就创建了线程。

【实例13.2】下面把前面举过的例子用这种方法重新编写。


01 ///创建一个主运行类

02 ///在主运行方法中,创建两个线程,让其交替运行

03 public class threadtest1

04 {

05 public static void main(String[]args)

06 {

07 compute t=new compute();

08 compute1 t1=new compute1();

09 t.start();

10 t1.start();

11 }

12 }

13 ///创建compute线程类

14 ///在这个线程类中,通过循环语句输出1~10十个整型数据

15 class compute extends Thread

16 {

17 int i=0;

18 public void run()

19 {

20 for(int i=0;i<10;i++)

21 {

22 System.out.println(i);

23 }

24 }

25 }

26 ///创建compute1线程类

27 ///在这个线程类中,通过循环语句输出说明性语句

28 class compute1 extends Thread

29 {

30 public void run()

31 {

32 for(int i=0;i<10;i++)

33 {

34 System.out.println("这个数字是:"+i);

35 }

36 }

37 }


【代码说明】第15~37行创建了两个线程,它们都继承自Thread类。第7~10行创建两个线程对象,并开始运行线程。

【运行效果】


0 这个数字是:0

1 这个数字是:1

2 这个数字是:2

3 这个数字是:3

4 这个数字是:4

5 这个数字是:5

6 这个数字是:6

7 这个数字是:7

8 这个数字是:8

9 这个数字是:9


说明 读者的运行结果可能不同,但没有关系。

创建方式虽然不一样,但运行效果仍然一样。下一节将通过一个稍微复杂的综合实例,让读者对线程的概念有一个更好的认识。通过这个综合实例,也可以复习前面讲过的一些知识,如接口、继承、多态、覆盖等,因为这些知识点在程序开发中一直会出现。