该文章属于JavaSE应掌握的部分,属于并发编程的基础
本人能力有限,如有遗漏或错误,敬请指正,谢谢
系列文章目录
阅读前面文章有助于更好的理解本文:
1.基于SpringBoot+Async注解整合多线程
文章目录
一、继承Thread类
创建一个类继承Thread类后,该类重写run()方法,表示这个类是一个线程类
public class MyThread extends Thread{
//线程调用的方法
@Override
public void run(){
}
}
创建线程实例,调用start()方法开启线程(不是run()方法)
public static void main(String[] args){
//创建MyThread对象
MyThread my1=new MyThread();
//启动线程
my1.start();
try {
Thread.sleep(5000);//线程睡眠5秒
} catch (InterruptedException e) {
e.getMessage();
}
System.out.println("主线程main结束");
}
总结:由于Java的继承是单继承,所以往往在项目中如果某个类需要继承一个抽象类重写方法,那么就不能继承Thread类了。(一般不使用,往往是学习中的第一个创建线程方式)
二、实现Runnable接口
创建一个类通过实现Runnbale接口,并重写其的run()方法
public class MyThread2 implements Runnbale{
//线程执行的方法
public void run(){
}
}
创建Thread对象后,将该类作为参数传递进去
注意:创建的Thread对象才是我们的线程对象,而线程执行的run方法则是调用传递参数里的run()方法
public static void main(String[] args){
MyThread2 myThread2=new MyThread2();
//创建Thread对象,传递参数
Thread thread=new Thread(myThread2);
thraed.start();//启动线程
try {
Thread.sleep(5000);//线程睡眠5秒
} catch (InterruptedException e) {
e.getMessage();
}
System.out.println("主线程main结束")
}
2.1 通过匿名内部类的方式传递
好处:不用多创建一个类,直接在创建Thread对象时通过匿名内部类的方式重写run()方法
public static void main(String[] args){
//创建Thread对象,传递匿名参数
Thread thread=new Thread(new MyThread2(){
@Override
public void run(){
//方法实现
}
});
thraed.start();//启动线程
}
2.2 Lambda写法
好处:以上写法的简洁写法,Jdk1.8以上版本
public static void main(String[] args){
Thread thread=new Thread(() -> {
//方法实现
});
}
总结:由于Java是可以实现多接口的(为了弥补单继承),所以创建线程可以采用这种方式,不会影响到普通类的继承
三、实现Callable接口
3.1 与Runnable接口的区别
在Callable接口中的call()方法作用是和run()一样的,是线程执行时调用的方法
优势在于:
1、从图中可以看出call()方法里有throws Exception,所以call()方法可以抛出异常,被外面的操作捕获,获取异常的信息
2、call()方法可以有返回值,所以我们在编写业务代码的时候,可以获取返回值
3、call()的返回值是泛型
3.2 使用方法
由于new Thread()里面的参数只能是Runnable类型,所以不能直接创建Callable实现类,那么需要有一个既实现了Callable接口又实现了Runnable接口的类FutureTask
FutureTask
①因为call()方法有返回值,那么在线程中获取返回值的方法,用FutureTask中的get()方法
②可以传递泛型,指定返回的类型
③FutureTask同时实现了Runnable、Future接口,它既可以作为Runnable被线程执行,也可以得到Callable的返回值。
④可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果
1.先创建FutureTask对象
2.用匿名内部类重写call方法=新建类实现Callable接口
3.将FutureTask对象作为参数传入Thread类中
4.启动线程,接受返回值用方法:futureTask.get()
public static void main(String[] args) throws InterruptedException, ExecutionException {
//指定返回值为String
FutureTask<String> futureTask=new FutureTask(new Callable() {
@Override
public String call() throws Exception {
return "thread线程call()方法返回值";
}
});
//传入参数
Thread t1=new Thread(futureTask);
t1.start();
String result=futureTask.get();//接受返回值
System.out.println(result);
}
关键点:使用get()方法会导致当前线程阻塞,只有结束方法才会执行主线程
总结:实现Callable接口功能比第二种方式更为强大,可以判断线程是否执行完毕或者接收返回值