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类的开销大于实现接口。