剖析JDK源码-Runnable-(9)
一、简述
Runnable直译就是“可运行的”,是实现多线程的关键,从上一篇的Thread就可以看出Thread是Runnable的一个实现类。
在潜意识里,记得创建线程有三种方式:继承Thread、实现Runnable、实现Callable;嗯,既然Thread已经实现了Runnable,那通过继承Thread就可以创建进程,为什么还要抽离一个接口呢?
二、接口类的声明和注解标记
@FunctionalInterface
public interface Runnable {
}
- interface 接口类。
- 注解:@FunctionalInterface
这是java 8新加入的一种注解,用来标记该接口是一个函数式编程接口。
函数式编程接口:指该接口有且只有一个抽象方法
但这种注解并不是必须的,如果加上了这个注解就必须满足他的条件,否则就会报错。
意在做一个标记使编译器更好的进行检查。
三、方法
public abstract void run();
- 整个接口类就一个抽象方法run();
连start()都没有,run()创建的线程,要怎么去启动这个线程呢?
- 错误示范
public class MyRunnableTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable("线程");
myRunnable.run();
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println(name+i);
}
}
}
- 正确示范
public class MyRunnableTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable("线程");
Thread t = new Thread(myRunnable);
t.start();
}
}
-
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println(name+i);
}
}
}
- 上面两段代码乍看运行结果竟然一样?但事实上第一种的MyRunnable.run()就是调用了一个普通的类方法。并没有开启一个新的线程。
- 所以不能说Runnable就是线程, 只能说Runnable 是创建线程的一种方式。
正确使用Runnable 创建线程的步骤:
1、新建一个实现Runnable 的类MyRunnable ,重写run()里面的操作。
2、实例化一个MyRunnable 类 myRunnable 。
3、实例化一个Thread对象,把myRunnable 传参给Thread。
4、启动thread。
- 最终还是要用Thread才能启动,做无用功?
其实不是的,事实上用继承Thread的方式创建线程往往是最少用,而实现Runnable 才是用的最多的,因为java在继承与实现上的限制不同:不允许多继承、允许多实现。
也就是说,如果我现在写的这个类已经继承了父类,又想实现多线程,那是不是鱼与熊掌不可兼得啦。但是实现接口却可以解决这个问题,而且还可以继续实现Callable。
这时应该知道抽离这个接口的作用了吧。