线程的创建相关
1. 创建线程的方式
关于线程创建的方式,网上各种说法都有。搞的我们毫无头绪,到底怎么才是正确的,怎么才是错误的。因此查询了oracle官方的解释,创建线程的方式一共只有两种:
- 集成Thread类 本质:重写run()方法
public class ThreadStyle extends Thread {
public static void main(String[] args) {
ThreadStyle threadStyle = new ThreadStyle();
threadStyle.start();
}
@Override
public void run() {
System.out.println("this is extends Thread to start create a thread");
}
}
- 实现Runable接口 本质:调用target.run()
public class RunableStyle implements Runnable {
public static void main(String[] args) {
Thread thread = new Thread(new RunableStyle());
thread.start();
}
@Override
public void run() {
System.out.println("this is implements runable to start create a thread");
}
}
一般来说,以上两种方式,用实现Runable接口的方式会更好一点:
- 如果使用集成Thread类的话,run方法没有和Thread类解耦
- 如果使用集成Thread类,每次执行一个任务,都需要创建一个独立的线程,消耗比较大
- 如果集成Thread类,则该类不能继续集成别的类
2. 同时包含两种情况
如果一个类同时集成Thread类,又包含一个实现Runnable接口的类,则它最终的运行结果会是什么呢?我们可以根据以下代码的运行结果做一下总结
public class AllStyle extends Thread {
public AllStyle(Runnable runnable) {
super(runnable);
}
@Override
public void run() {
System.out.println("I am from Override");
}
public static void main(String[] args) {
AllStyle allStyle = new AllStyle(()->{
System.out.println("I am from runnable");
});
allStyle.start();
}
}
如果当前类重写run方法的话,我们会得到I am from Override这个结果,如果不重写则会得到I am from runnable这个结果。这就说明,当两者同时出现的时候,以重写的方法为准。
其原因是因为:
这是Thread类内部的run方法,target是Runable对象,如果通过构造方法传入,则会将其赋值给target。当我们定义的类重写Thread之后,则不会在有调用target的地方。因此当两种形式同时存在时,便会以子类的重写方法为准
@Override
public void run() {
if (target != null) {
target.run();
}
}
因此准确的讲,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式
- 实现Runnable接口的run方法,并把Runnable实例传给Thread类
- 重写Thread的run方法(集成Thread类)
3. 网上说的创建线程的方式
其实用线程池、FutrueTask、匿名类等等所有方式,其本质都是基于Runnable或者Thread类实现的