实现多线程方式一:继承Thread类

方法介绍

方法名

说明

void run()

在线程开启后,此方法将被调用执行

void start()

使此线程开始执行,Java虚拟机会调用run方法()

实现步骤

  • 定义一个类MyThread继承Thread类
  • 在MyThread类中重写run()方法
  • 创建MyThread类的对象
  • 启动线程

代码演示

public class MyThread extends Thread {
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(i);
}
}
}

public class MyThreadDemo {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();

// my1.run();
// my2.run();

//void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
my1.start();
my2.start();
}
}

两个小问题

  • 为什么要重写run()方法?
  • 因为run()是用来封装被线程执行的代码
  • run()方法和start()方法的区别?
  • run():封装线程执行的代码,直接调用,相当于普通方法的调用
  • start():启动线程;然后由JVM调用此线程的run()方法

实现多线程方式二:实现Runnable接口

Thread构造方法

方法名

说明

Thread(Runnable target)

分配一个新的Thread对象

Thread(Runnable target, String name)

分配一个新的Thread对象

实现步骤

  • 定义一个类MyRunnable实现Runnable接口
  • 在MyRunnable类中重写run()方法
  • 创建MyRunnable类的对象
  • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
  • 启动线程

代码演示

public class MyRunnable implements Runnable {

@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}

public class MyRunnableDemo {
public static void main(String[] args) {
//创建MyRunnable类的对象
MyRunnable my = new MyRunnable();

//创建Thread类的对象,把MyRunnable对象作为构造方法的参数
//Thread(Runnable target)
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
//Thread(Runnable target, String name)
Thread t1 = new Thread(my,"高铁");
Thread t2 = new Thread(my,"飞机");

//启动线程
t1.start();
t2.start();
}
}

多线程的实现方案有两种

  • 继承Thread类
  • 实现Runnable接口

相比继承Thread类,实现Runnable接口的好处

  • 避免了Java单继承的局限性
  • 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想

实现多线程方式三:实现Callable接口

实现Callable接口,重写call()方法

Callable接口是属于Executor,对比与Runnable接口功能的区别是:

  • Callable可以在任务结束后提供一个返回值,Runnable没有这个功能
  • Callable中的call()方法可以抛出异常,而Runnable的run()方法不能抛出异常
  • 运行Callable可以拿到一个Future对象,Future独享表示异步计算的结果,它提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下,就可以使用Future来监视目标线程调用call()方法的情况,放调用Future的get()方法以获取结果时,当前线程就会阻塞,知道call()方法结束返回结果。

代码演示

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MyThread implements Callable<String> {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();

Future<String> future = executorService.submit(new MyThread());
try {
System.out.println("waiting thread to finish");
System.out.println(future.get());
}catch (Exception e){
e.printStackTrace();
}
}

@Override
public String call() throws Exception {
return "创建多线程方法三";
}
}

推荐实现多线程的方法–实现Runnable接口

  • Thread类中定义了多种方法可以被派生类使用或重写,但是只有run()方法必须被重写的,在run()方法中实现啊这个线程的主要功能,这就是Runnable接口所需实现的方法
  • 通过继承Thread的实现方法与实现Runnable接口的效果相同,并且Java只能是单继承、多实现,如果一个类中已经继承其他所需的类,那实现一个接口是必须的。