创建线程的三种方式
一、继承Thread类
继承Thread类,如果不重写run方法,不会报错。
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("我是MyThread线程......");
}
public static void main(String[] args) {
System.out.println("我是main线程.......");
//MyThread t1 = new MyThread();
//t1.start();
new MyThread().start();
}
}
打印结果:
我是main线程.......
我是MyThread线程......
二、实现Runnable接口
实现Runnable接口必须实现run()方法,不然会报错。
public class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("我是MyThread2线程......"+Thread.currentThread().getName());
}
public static void main(String[] args) {
/*
MyThread2 t = new MyThread2();
Thread thread = new Thread(t);
thread.start();
*/
//java.lang.Thread.Thread(Runnable target)
//线程名字默认为Thread-0,Thread-1,...,Thread-n
new Thread(new MyThread2()).start();
new Thread(new MyThread2()).start();
//java.lang.Thread.Thread(Runnable target, String name)
//自定义线程名
new Thread(new MyThread2(),"实现Runnable接口的线程").start();
}
}
打印结果:
我是MyThread2线程......Thread-0
我是MyThread2线程......Thread-1
我是MyThread2线程......实现Runnable接口的线程
三、使用Callable创建
callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能更强大
- call()方法可以有返回值
- call()方法可以声明抛出异常
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MyThread3 implements Callable<String>{
public static void main(String[] args) throws InterruptedException, ExecutionException {
//FutureTask可用于包装Callable或Runnable对象。
//因为FutureTask实现Runnable ,一个FutureTask可以提交到一个Executor执行。
FutureTask<String> ft = new FutureTask<>(new MyThread3());
//在两个线程里传入同一个futureTask,只会执行一次(第一个)
new Thread(ft,"线程1").start();
new Thread(ft,"线程2").start();
//Callalble接口支持返回执行结果,需要调用FutureTask.get()得到
System.out.println(ft.get());
}
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "Callable finished....";
}
}
执行结果:
线程1
Callable finished....
有关API描述:
- 该
Executors
类包含的实用方法,从其他普通形式转换为Callable
类。
- 一个
FutureTask
可用于包装Callable
或Runnable
对象。 因为FutureTask
实现Runnable
,一个FutureTask
可以提交到一个Executor
执行。
面试题:Runnable和Callable实现线程方式有那些区别?
- Callable接口执行结束有返回值,Runnable接口没有返回值。
- Callable接口的call()方法允许抛出异常,Runnable接口run()方法的异常只能消化,不能继续网上抛。
Callable接口只支持返回执行结果,需要调用FutureTask.get()获取。
此方法会阻塞主程序继续往下执行。