Java的线程启动主要有三种方式:
一、继承Thread类
public class MyThread extends Thread {
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "执行" + i);
}
//输出当前线程对象名称和执行次数
}
}
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
}
创建步骤:
1、创建线程类,并继承Thread类
2、重写子类的run方法,实现线程的运行逻辑结构
3、在main方法中创建自定义线程实例
4、通过MyThread.start()启动
注意:
1.要调用start的方法来创建新的线程实例,否则如同调用类的方法,仍在当前主线程内执行,无新的线程的创建。
2.一个线程只能启动一次
两个重要的方法:
①Thread.currentThread(),这是Thread类的静态方法,该方法返回当前的线程对象
②getName(),作用于Thread类的实例,返回当前线程的名称。在默认情况下,主线程的名称为main,用户启动的多线程的名称依次为Thread-0,Thread-1,Thread-3..Thread-n等。
二、实现Runnable接口
public class Thread2 implements Runnable{
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "执行" + i);
}
}
}
public class Main {
public static void main(String[] args) {
new Thread(new Thread2()).start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "执行" + i);
}
}
}
创建线程的步骤:
1、自定义线程类,实现Runnable方法
2、重写run()方法
3、将Runnable实现类的具体对象作为实例传入Thread()方法。该Thread对象才是真正的线程对象
ps:main函数中名没有直接执行Thread2的run方法,而是将Thread2填入到了Thread中,使用start方法来启动。Runable实现类里包含run方法,仅仅作为线程执行体,而实际的线程对象依然是Thread实例对象,Thread为真正创建线程的对象。
4、Thread对象通过start()启动线程
通过继承Runnable接口,可以通过匿名内部类创建线程,与上述类似。
Main类:
public class Main {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "执行" + i);
}
}
}).start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "执行" + i);
}
}
}
只是不用额外再创建一个线程类,节省了一定的内存开支。
三、实现Callable接口
public class MyCallable implements Callable<Integer> {
public Integer call() {
return 123;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread thread = new Thread(ft);
thread.start();
System.out.println(ft.get());
}
Callable接口实际上是属于Executor框架中的功能类,Callable接口与Runnable接口的功能类似,但提供了比Runnable更加强大的功能。
1.Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
2.Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
实现接口和继承Thread类的区别:
1.设计模式上:
Thread时单继承的,而接口是可以实现多个接口,所以通过接口实现仍可以继承其他父类。
2.操作分析上:
Thread继承方式直接通过创建线程的对象来启动线程,而继承接口则需要先创建接口实例的对象,再将对象传入到Thread()方法中来启动线程。
3.资源共享:
从多线程分享同一个资源上分析,继承方法无法做到,而实现接口的方法则可以做到。
4.开销
类可能只需要可执行就行,继承一个Thread类的开销大于实现接口。