线程1(实现线程的1种方法)
1. 基本
1. 实现 Runnable 接口:
public class RunnableThread implements Runnable {
@Override
public void run() {
System.out.println("用实现Runnable接口实现线程");
}
}
2. 继承 Thread 类
public class ExtendsThread extends Thread{
@Override
public void run() {
System.out.println("用Thread类实现线程");
}
}
- 启动方式:
public class Test {
public static void main(String[] args) {
ExtendsThread extendsThread = new ExtendsThread();
extendsThread.start();
RunnableThread runnableThread = new RunnableThread();
new Thread(runnableThread).start();
}
}
- 线程池创建线程
- 有返回值的 Callable 创建线程
- 定时器 Timer
- 匿名内部类创建线程
- 比如线程池或是定时器,它们仅仅是在 new Thread() 外做了一层封装
2. 实现线程只有一种方式
public void run() {
if (target != null) {
target.run();
}
}
- 实现 Runnable 接口,首先,启动线程需要调用 start() 方法,而 start() 方法最终还会调用 run() 方法:
第 1 行代码 if (target != null) ,判断 target 是否等于 null,如果不等于 null,就执行第 2 行代码 target.run(),而 target 实际上就是一个 Runnable,即使用 Runnable 接口实现线程时传给Thread类的对象。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
- 继承 Thread 方式,会把上述的 run() 方法重写,重写后 run() 方法里直接就是所需要执行的任务,但它最终还是需要调用 thread.start() 方法来启动线程,而 start() 方法最终也会调用这个已经被重写的 run() 方法来执行它的任务,事实上创建线程只有一种方式,就是构造一个 Thread 类,这是创建线程的唯一方式。
- 本质上,实现线程只有一种方式,而要想实现线程执行的内容,却有两种方式,也就是可以通过 实现 Runnable 接口的方式,或是继承 Thread 类重写 run() 方法的方式,把我们想要执行的代码传入,让线程去执行
3. 实现 Runnable 接口比继承 Thread 类实现线程要好
- Runnable 里只有一个 run() 方法,它定义了需要执行的内容,在这种情况下,实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。
- 某些情况下可以提高性能,使用继承 Thread 类方式,每次执行一次任务,都需要新建一个独立的线程,执行完任务后线程走到生命周期的尽头被销毁,如果还想执行这个任务,就必须再新建一个继承了 Thread 类的类,如果我们使用实现 Runnable 接口的方式,就可以把任务直接传入线程池,使用一些固定的线程来完成任务,不需要每次新建销毁线程,大大降低了性能开销。
- Java 语言不支持双继承,如果我们的类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,这样一来,如果未来这个类需要继承其他类实现一些功能上的拓展,它就没有办法做到了,相当于限制了代码未来的可拓展性。
- 如果使⽤线程时不需要使⽤Thread类的诸多⽅法,显然使⽤Runnable接⼝更为轻量。
解耦,权责分明
重复任务,新建线程开销大
不支持双继承,降低代码拓展性
4. java不可以直接开启线程
只有用start()才可以开启新线程:
但是底层调用C++
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
// 本地方法,底层的C++,java无法直接操作硬件
private native void start0();