JDK 中已提供了对多线程的支持,可以很方便 实现多线程编程,主要有两种方式:一种是继承 Thread 类,另一种是实现 Runnable 接口。
继承 Thread 类
先查看 Thread 类源码,了解其结构:public class Thread implements Runnable { ... }。
Thread 类实现了 Runnable 接口,它们之前具有多态关系。使用继承 Thread 不支持多继承;若要支持多继承,可以使用实现 Runnable 接口的方式,这两种创建线程的方式在工作时性质是一样的,没有本质区别。
通过继承 Thread 类来使用线程:
- 继承 Thread 类。
- 重写 run 方法。
- 在 run 方法里面写任务代码。
- 创建线程对象。
- 调线程对象和 start() 方法开启线程,内部会 自动执行 run() 方法。
public class RunThread {
public static void main(String[] args) {
// 4.创建 Thread 类的子类对象
MyThread mt = new MyThread();
// 5.调用start()方法开启新线程,系统默认调用run方法
mt.start();
System.out.println("运行结束!");
}
}
/**
* 创建新执行线程方法一:
* 1.继承Thread类
* 2.重写run方法
* 3.将要执行的代码写在run方法中
*/
class MyThread extends Thread {
public void run() {
System.out.println("This is MyThread2 ");
}
}
输出:
运行结束!
This is MyThread
结果中,run() 方法里的执行的时间较 main 线程更晚,意味着使用多线程时,代码的运行结果顺序与代码执行顺序或调用顺序无关,并且执行 start() 方法的顺序不代表线程启动的顺序。线程是个子任务,由 CPU 以不确定的方式,或者说随机的访问调用线程中的 run 方法。
实现 Runnable 接口
查看 Thread 类的构造方法,有两个构造方法可以传入 Runnable 接口对象。
- 定义 Runnable 接口的实现。
- 重写 run 方法。
- 在run方法中写任务代码。
- 创建 Runnable 接口对象。
- 创建 Thread 对象, 传入 Runnable 接口对象。
- 调用 start() 开启新线程, 内部会自动调用 Runnable 的run()方法。
public class RunRunnableImpl {
public static void main(String[] args) {
// 4.创建 Runnable 接口对象
MyRunnable mr = new MyRunnable();
// 5.将其当作参数传递给Thread的构造函数
Thread thread = new Thread(mr);
// 6.开启线程
thread.start();
System.out.println("main 运行结束");
}
}
/**
* 1.定义一个类实现Runnable接口
* 2.重写run方法
* 3.多线程执行代码写在run()方法里面
* 4.调用 start() 方法
*/
class MyRunnable implements Runnable {
@Override
// 2.重写run方法
public void run() {
System.out.println("This is MyRunnable!");
}
}
从 Thread 构造方法 public Thread(Runnable target) 可以看出,其除了传入 Runnable 接口对象,还可以传入一个 Thread 对象,这样完全可以将一个 Thread 对象中的 run() 方法交由其它的线程调用。
查看 Thread 原码可以了解到:
- Thread 类的构造方法,传递了 Runnable 接口对象。
- 通过 init() 方法找到传递的 target 给成员变量的 target 赋值。
- 查看 run 方法,发现 run 方法中有判断,如果 target 不为 null 就会调用 Runnable 接口对象的 run 方法。
两种实现方式区别
查看源码的区别:
- 继承 Thread:由于子类重写了 Thread 类的 run(), 当调用 start() 时, 直接找子类的 run() 方法。
- 实现 Runnable: 构造函数中传入了 Runnable 接口对象, 成员变量记住了它, start() 调用 run() 方法时内部判断成员变量 Runnable 接口对象是否为空,不为空编译时看的是 Runnable 的 run() ,运行时执行的是实现类的 run() 方法
继承 Thread:
- 好处是:可以直接使用 Thread 类中的方法,代码简单。
- 弊端是:如果已经有了父类,就不能用这种方法。
实现Runnable接口:
- 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的。
- 弊端是:不能直接使用 Thread 中的方法需要先获取到线程对象后,才能得到 Thread 的方法,代码略有复杂。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载