在学习如何实现多线程前,先来看看Thread类的结构,如下:
从上面的源代码可以发现,Thread类实现了Runnable接口,它们之间具有多态关系。
其实,使用继承Thread类的方式实现多线程,最大的局限就是不支持多继承,因为Java语言的特点就是单继承,所以为了支持多继承,完全可以实现Runnable接口的方式,一边实现一边继承。但用这两种方式创建的线程在工作时的性质是一样的,没有本质的区别。
Thread类常用构造方法如表8-1所示。
表8-1 Thread类常用构造方法表
继承Thread类实现线程的语法格式如下:
线程实现的业务代码需要放到run()方法中。当一个类继承Thread类后,就可以在该类中覆盖run()方法,将实现线程功能的代码写入run()方法中,然后同时调用Thread类的start()方法执行线程,也就是调用run()方法。
Thread对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run()方法中。当执行一个线程程序时,就会自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序。主方法线程启动由Java虚拟机负责,开发人员负责启动自己的线程。
如下代码演示了如何启动一个线程:
注意:如果start()方法调用一个已经启动的线程,系统将会抛出Illegal ThreadStateException异常。
【例8-1】 编写一个Java程序演示线程的基本使用方法。这里创建的自定义线程类为My Thread,此类继承自Thread,并在重写的run()中输出一行字符串。My Thread类代码如下所示:
接下来编写启动My Thread线程的主方法,代码如下:
运行上面的程序将看到如下所示的运行效果:
(www.xing528.com)
从上面的运行结果来看,My Thread类中run()方法执行的时间要比主线程晚。这也说明在使用多线程技术时,代码的运行结果与代码执行顺序或调用顺序是无关的。同时也验证了线程是一个子任务,CPU 以不确定的方式,或者说以随机的时间来调用线程中的run()方法,所以就会出现先打印“运行结束!”,后输出“这是线程类My Thread”这样的结果了。
【例8-2】 上面介绍了线程的调用具有随机性,为了更好地理解这种随机性,这里编写了一个案例进行演示。
(1)首先创建自定义的线程类My Thread,代码如下:
(2)接下来编写主线程代码,在这里除了启动上面的My Thread 线程外,还实现了My Thread线程相同的功能。主线程的代码如下:
在上述代码中,为了展现出线程具有随机特性,所以使用随机数的形式来使线程得到挂起的效果,从而表现出CPU 执行哪个线程具有不确定性。
My Thread类中的start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程对象的run()方法。这个过程其实就是让系统安排一个时间来调用Thread中的run()方法,也就是使线程得到运行,启动线程,具有异步执行的效果。
如果调用代码thread.run()就不是异步执行了,而是同步,那么此线程对象并不交给“线程规划器”来处理,而是由main主线程来调用run()方法,也就是必须等run()方法中的代码执行完后才可以执行后面的代码。
这种采用随机数延时调用线程的方法又称为异步调用,程序运行的效果如下所示:
【例8-3】 除了异步调用之外,同步执行线程start()方法的顺序不代表线程启动的顺序。下面创建一个案例演示同步线程的调用。
(1)首先创建自定义的线程类My Thread,代码如下:
(2)接下来编写主线程代码,在这里创建10个线程类My Thread,并按顺序依次调用它们的start()方法。主线程的代码如下:
程序运行后的结果如下所示,从运行结果中可以看到,虽然调用时数字是有序的,但是由于线程执行的随机性,导致输出的数字是无序的,而且每次顺序都不一样。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。