在java中实现多线程的两途径:继承Thread类,实现Runable接口(Callable)
继承类Thread是支持多线程的功能类,只要创建一个子类就可以实现多线程的支持。
所有的java程序的起点是main方法,所以线程一定有自己的起点,那这个起点就是run方法;因为多线程的每个主体类之中必须重写Thread的run方法。
public void run()
这个run方法没有返回值,那就说明线程一旦开始就一直执行不能返回内容。
编写一个测试线程类继承Thread 在run方法中写一个循环输出语句;
分析:创建多个测试类启动线程,多个线程回想进程一样,轮流抢占资源,所以多线程程序应该是多个线程彼此交替执行;
class TestThread extends Thread{//内部类
String name;
TestThread( String name){
this.name=name;
}
@Override
public void run(){
for(int i=1;i<10;i++) {
System.out.print(name + i);
}
}
}
public class MyThread {
public static void main(String[] args) {
new TestThread("A").run();
new TestThread("B").run();
new TestThread("C").run();
}
}
上面是调用Thread的run方法,但是查看日志输出并不是交替输出如下
A1A2A3A4A5A6A7A8A9B1B2B3B4B5B6B7B8B9C1C2C3C4C5C6C7C8C9
本线程类的功能是进行循环的输出操作,所有的线程与进程是一样的,都必须轮流去抢占资源,所以多线程的执行应该是多个线程彼此交替执行,也就是说如果调用了run方法,那么并不能够启动多线程,多线程启动的唯一方法是调用Thread的start方法(调用此方法执行的是run方法体)。
修改如下:
public class MyThread {
public static void main(String[] args) {
new TestThread("A").start();
new TestThread("B").start();
new TestThread("C").start();
}
}
运行结果
B1C1A1C2C3B2B3C4A2A3A4A5A6A7A8A9C5C6C7B4B5B6B7B8B9C8C9
疑问?为什么多线程的启动不是调用run方法而必须调用start方法?
找到java的源代码:在jdk安装的目录找到src压缩包解压,在java.lang包里的Thread的start方法如下:
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
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 */
}
}
}
private native void start0();
在start方法里,开始的地方有IllegalThreadStateException异常抛出,防止线程启动重复。
发现在start方法里面要调用一个start0方法,而且此方法的结构和抽象方法类似,使用了native声明,在Java开发里面有一门技术称为JNI技术(Java Native Interface),这门技术的特点:是使用Java调用本机操作系统提供的函数。但是有个缺点:不能够离开特定的操作系统。
总结:使用Thread类的start方法不仅仅启动多线程的执行代码,还要从不同操作系统中分配资源。
Java具有单继承局限,所有的Java程序针对类的继承都应该是回避,那么线程也一样,为了解决单继承的限制,因此才有Runnable接口代码如下:
@FunctionalInterface
public interface Runnable{
public void run();
}
这个接口有点特殊是@FunctionalInterface注解修饰的,这是函数式接口,特征是:一个接口只有一个方法。
接口中的方法都是public权限,不存在默认权限。
使用方法:让一个类实现Runnable接口即可,并且也需要覆写run()方法。
疑问:但是此接口只有run方法,没有start方法,怎么启动多线程呢?
不管任何情况下,如果要想启动多线程一定要依靠Thread类完成,在Thread类中有参数是Runnable参数的构造方法:
可以创建一个参数是Runnable实现类的Thread类,调用start方法启动。
public class MyThread {
public static void main(String[] args) {
new Thread(new TestThread("A")).start();
new Thread(new TestThread("B")).start();
new Thread(new TestThread("C")).start();
}
}
总结:实现Runnable接口来写多线程的业务类,用Thread来启动多线程。