一、创建多线程的方式一:继承Thread类
1. 创建多线程方式一的步骤
- 定义类继承Thread类
- 重写Thread类的run方法
- 在主线程中创建线程对象
- 线程对象调用start()方法启动子线程
2. 案例
public class AutoMessages extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程输出:"+i
);
}
}
}
@SpringBootTest
public class ThreadTest {
@Test
public void testThread(){
AutoMessages autoMessages = new AutoMessages();
autoMessages.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程输出:"+i);
}
}
}
3.知识总结
- 为什么不直接调用run方法,而是调用start启动线程
- 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行
- 只有调用start方法才是启动一个新的线程执行
2. 把主线程任务放在子线程之前了
- 这样主线程任务先执行,才会创建子线程。 相当于是一个单线程的效果了。
二、创建多线程的方式二:实现Runnable接口
1. 创建多线程方式二的步骤
- 定义类实现Runnable接口
- 实现Runnable接口的run方法
- 在主线程中创建自定义类的对象
- 在主线程中创建线程对象,参数为Runnable类型
- 线程对象调用start()方法启动子线程
2. 案例
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("子线程输出:"+i);
}
}
}
@Test
public void testRunnable() {
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程输出:"+i);
}
}
3. 改良版:匿名类与lambda表达式
@Test
public void testRunnable01() {
//改造一:匿名类
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程01输出:"+i);
}
}
};
Thread t1 = new Thread(runnable);
t1.start();
//改造二:
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程02输出:"+i);
}
}
});
t2.start();
//改造三:使用lambda表达式
new Thread(()-> {
for (int i = 0; i < 5; i++) {
System.out.println("子线程03输出:" + i);
}
}).start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程输出:"+i);
}
}
}
4、Thread与Runnable的比较
1. 通过继承Thread是把线程和任务合并在一起了。而通过实现runnable是把线程和任务分离。用Runnable更容易与线程池等高级API配合。用Runnable让任务类脱离了Thread继承体系,更灵活。
2. 通过继承Thread和实现Runnable两种方式创建多线程都存在一个问题:他们重写的run方法均不能直接返回结果。不适合需要返回线程执行结果的业务场景。