我们创建线程池一般有四种方式,分别是:
1.继承Thread类,重写run()方法;
2.实现Runnable接口,重写run()方法;
3.实现Callable接口,重写call()方法;
4.使用线程池创建线程;
本文就介绍下前3种创建线程的方式,第4种使用线程池的方式,大家可以查看下Java之线程池入门
一、继承Thread类
步骤:
1.创建一个类继承Thread类,重写其run()方法,在run()方法中编写需要执行的任务;
2.创建继续Thread类的对象;
3.调用其对象的start()方法,该方法表示启动一个线程,线程处于就绪状态,如果获取到cpu执行权,则会调用run()方法,执行对应的任务;
注意:如果调用run()方法,就是普通的方法调用;
Demo1:
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println("继承thread类实现线程---");
}
}
运行结果:
继承thread类实现线程---
二、实现Runnable接口
步骤:
1.创建一个类,实现Runnable接口,重写run()方法,编写需要执行的代码;
2.创建一个Runnable接口实现类的对象;
3.将此对象作为形参传递到Thread类的构造器中,创建Thread类的对象,调用start()方法,启动线程;
Demo2:
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("实现Runnable接口来创建线程---");
}
}
运行结果:
实现Runnable接口来创建线程---
继承方式和这种实现接口的方式的联系和区别:
1.联系:public class Thread implements Runnable, 继承Thread 方式中Thread也实现了Runnable接口
2.实现接口的方式要优先继承方式:
- 避免了java只能单个继承的局限性
- 如果多个线程要操作同一份资源或者数据,使用实现接口的方式更加合适。
三、实现Callable接口
步骤:
1.创建Callable接口的实现类,并实现call()方法,该方法具有返回值,并且可以抛异常;
2.创建Callable实现类的实例,并使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
3.使用FutureTask对象作为Thread对象的target创建并启动新线程;
4.调用FutureTask对象的get()方法来获取子线程执行结束后的返回值;
demo3:
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
FutureTask<Integer> futureTask = new FutureTask<>(myThread);
new Thread(futureTask).start();
try {
Integer integer = futureTask.get();
System.out.println("执行结果:"+integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("实现Callable接口来创建线程---");
Integer i = 6/2;
return i;
}
}
运行结果:
实现Callable接口来创建线程---
执行结果:3
实现Runnable和实现Callable接口的方式基本相同,
不过是后者执行call()方法有返回值,并且可以抛出异常,前者线程执行体run()方法无返回值.
Callable 和 Runnable接口的区别
- Callable规定的方法是call(),而Runnable规定的方法是run()。
- Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
- call()方法可抛出异常,而run()方法是不能抛出异常的。
我们看到Runnable和Callable传到Thread类的构造器中表面上方式是“不一样”的,我们看到Thread类的构造器:
我们上面使用的都是public Thread(Runnable target)构造器,实现Runnable方式直接将其实现类的对象传入即可;但是实现Callable接口,我们使用的FutureTask来保证实现Callable接口类的对象,在传入Thread构造器中,那FutureTask和Runnable有什么关系呢?
我们点到FutureTask类的源码中可以发现其实现了RunnableFuture接口
然后继续点进RunnableFuture接口的源码中,我们发现其继承了Runnable接口。
看到这里不知道大家发现没有,上面三种方式都和Runnable接口有联系;Thread类是实现Runnable,Callable封装成FutureTask,FutureTask实现RunnableFuture,RunnableFuture继承Runnable,所以Callable也算是一种Runnable,所以三种实现方式本质上都是Runnable实现。