创建多线程的方式
- 继承 Thread类
- 实现 Runable接口
- 实现 Callable接口
- 线程池
继承 Thread类
创建Thread的子类,重写run()方法,然后启动Thread类
public class Test {
public static void main(String[] args) {
// 第二步:创建Thread子类的对象,通过对象调用start方法(启动当前线程)。
new MyThread().start();
//再启动一个多线程,要重新创建一个对象去调用start方法
new MyThread().start();
}
}
//第一步:创建一个Thread类的子类,
class MyThread extends Thread {
//子类中重写Thread类的run()方法。将此线程执行的操作,声明在run方法中。
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
}
}
实现 Runable接口
创建Runable的实现类,重写run()方法,包装成Thread,然后启动Thread类。
优先选择实现runable接口的方式,原因:接口没有类的单继承性的局限性,
public class Test {
public static void main(String[] args) {
// 将Runnable实现类作为Thread的构造参数传递到Thread类中,然后启动Thread类
MyRunnable runnable = new MyRunnable();
new Thread(runnable).start();
}
}
//第一步:创建一个实现runable接口的类
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
}
}
其它变体写法:
public class Test{
public static void main(String[] args) {
// 匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
}
}).start();
// 尾部代码块, 是对匿名内部类形式的语法糖
new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
}
}.start();
// Runnable是函数式接口,所以可以使用Lamda表达式形式
Runnable runnable = () -> {System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());};
new Thread(runnable).start();
}
}
实现 Callable接口
实现Callable接口,重写call()方法,然后包装成FutureTask, 再然后包装成Thread。然后启动Thread类。
Callable:有返回值,能取消线程,可以判断线程是否执行完毕。
public class Test {
public static void main(String[] args) throws Exception {
// 将Callable包装成FutureTask,FutureTask也是一种Runnable
MyCallable callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
// get方法会阻塞调用的线程
Integer sum = futureTask.get();
System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");
int sum = 0;
for (int i = 0; i <= 100000; i++) {
sum += i;
}
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
return sum;
}
}
总结:当线程不需要返回值时使用Runnable,需要返回值时就使用Callable,一般情况下不直接把线程体代码放到Thread类中,一般通过Thread类来启动线程
Thread类是实现Runnable,Callable封装成FutureTask,FutureTask实现RunnableFuture,RunnableFuture继承Runnable,所以Callable也算是一种Runnable,所以三种实现方式本质上都是Runnable实现