创建线程的几种方式
文章目录
- 创建线程的几种方式
- 一、继承 Thread 类
- 二、实现 Runnable 接口
- 三、实现 Callable 接口,并结合 Future 实现
- 四、通过线程池创建线程
- 五、前三种创建线程方式对比
- 继承Thread
- 实现Runnable接口
- 实现Callable接口
- 参考链接
一、继承 Thread 类
通过继承 Thread 类,并重写它的 run 方法,我们就可以创建一个线程。
- 首先定义一个类来继承 Thread 类,重写 run 方法。
- 然后创建这个自定义类的对象,并调用 start 方法启动线程。
/**
* 多线程实现的第一种方法,继承Thread
*
*/
//1.自定义一个类,继承java.lang包下的Thread类
class MyThread extends Thread {
//2.重写run方法
public void run() {
//3.将要在线程中执行的代码编写在run方法中
for(int i = 0; i < 1000; i++) {
System.out.println("monkey");
}
}
}
public class ThreadTest01 extends Thread {
public static void main(String[] args) {
//4.创建上面自定义类的对象
//创建一个线程
MyThread mt = new MyThread();
//5.调用start方法启动线程
mt.start();
//将循环的次数设置多一些,否则还没等到CPU切换就已经打印完成了
for(int i = 0; i < 1000; i++) {
System.out.println("1024");
}
}
}
二、实现 Runnable 接口
通过实现 Runnable ,并实现 run 方法,也可以创建一个线程。
- 首先定义一个类实现 Runnable 接口,并实现 run 方法。
- 然后创建 Runnable 实现类对象,并把它作为 target 传入 Thread 的构造函数中
- 最后调用 start 方法启动线程。
/**
* 多线程实现的第二种方法,实现Runnable接口
*
*/
// 1.自定义一个类实现java.lang包下的Runnable接口
class MyRunnable implements Runnable {
// 2.重写run方法
@Override
public void run() {
// 3.将要在线程中执行的代码编写在run方法中
for (int i = 0; i < 1000; i++) {
System.out.println("monkey");
}
}
}
public class ThreadTest02 {
public static void main(String[] args) {
// 4.创建上面自定义类的对象
MyRunnable mr = new MyRunnable();
// 5.创建Thread对象并将上面自定义类的对象作为参数传递给Thread的构造方法
Thread t = new Thread(mr);
//6.调用start方法启动线程
t.start();
for (int i = 0; i < 1000; i++) {
System.out.println("1024");
}
}
}
三、实现 Callable 接口,并结合 Future 实现
- 首先定义一个 Callable 的实现类,并实现 call 方法。call 方法是带返回值的。
- 然后通过 FutureTask 的构造方法,把这个 Callable 实现类传进去。
- 把 FutureTask 作为 Thread 类的 target ,创建 Thread 线程对象。
- 通过 FutureTask 的 get 方法获取线程的执行结果。
import java.util.Random;
import java.util.concurrent.Callable;
/**
* 多线程实现的第三种方法,实现Callable接口 优点: 可以获取返回值 可以抛出异常
*/
//1.定义一个类实现Callable<V>接口
public class MyCallable implements Callable<Integer> {
// 2.重写call方法
@Override
public Integer call() throws Exception {
// 3.将要执行的代码写在call方法中
//返回一个随机数
Random r = new Random();
int num = r.nextInt(100);
return num;
}
}
测试类:
MyCallable mc = new MyCallable();
//这里的泛型要跟MyCallable中的泛型一致
FutureTask<Integer> task = new FutureTask<>(mc);
//创建线程对象
Thread t = new Thread(task);
t.start();
//获取线程的运算结果
Integer result = task.get();
System.out.println(result);
lambda写法:
FutureTask<Integer> task = new FutureTask<>(() -> {
Random r = new Random();
int num = r.nextInt(100);
return num;
});
//创建线程对象
Thread t = new Thread(task);
t.start();
//获取线程的运算结果
Integer result = task.get();
System.out.println(result);
四、通过线程池创建线程
此处用 JDK 自带的 Executors 来创建线程池对象。
- 首先,定一个 Runnable 的实现类,重写 run 方法。
- 然后创建一个拥有固定线程数的线程池。
- 最后通过 ExecutorService 对象的 execute 方法传入线程对象。
五、前三种创建线程方式对比
继承Thread
优点 : 可以直接使用Thread类中的方法,代码简单
缺点 : 继承Thread类之后就不能继承其他的类
实现Runnable接口
优点 : 即使自定义类已经有父类了也不受影响,因为可以实现多个接口
缺点 : 在run方法内部需要获取到当前线程的Thread对象后才能使用Thread中的方法
实现Callable接口
优点:可以获取返回值,可以抛出异常
缺点:代码编写较为复杂
参考链接
链接: 面试官问我:创建线程有几种方式?我笑了
链接: 多线程创建的三种方式对比