目录
Thread 线程
视频地址:https://www.bilibili.com/video/BV1LG4y1T7n2/?p=5&vd_source=e33a356475cf6a18a9f6345f4e44a209
一、线程创建的三种方式
方式一:继承Thread类的方式进行实现
- 自己定义一个类继承Thread,其实Thread也是实现Runnable接口
- 重写run方法
- 创建子类的对象,并启动线程
public class MyThread extends Thread {
/**
* * 线程实现的方式一:
* * 1. 自己定义一个类继承Thread
* * 2. 重写run方法
* * 3. 创建子类的对象,并启动线程
*/
private int x = 0;
@Override
public void run() {
// 书写执行代码
for (int i = 0; i < 10; i++) {
System.out.println(this.getName() + " x : " + (this.x++));
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
// 线程名字可以通过 t.setName() 来设置
t1.setName("线程一");
t2.setName("线程二");
t1.start();
t2.start();
System.out.println("main方法执行结束");
}
}
方式二:实现Runnable接口的方式进行实现
- 自己定义一个类实现Runnable接口
- 重写里面的run方法
- 创建自己类的对象
- 创建一个Thread类的对象,并开启线程
@NoArgsConstructor
public class MyRunnable implements Runnable {
@Override
public void run() {
// 获取当前线程的名称
String strName = Thread.currentThread().getName();
// n值代表循环多少次
int n = 11;
for (int i = 0; i < n; i++) {
System.out.println("当前线程的名字是:" + strName + ",第" + i + "次执行!");
}
}
public static void main(String[] args) {
// 创建myRunnable任务
MyRunnable myRunnable = new MyRunnable();
// 创建线程对象,将任务传递给线程
Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable);
t1.setName("线程一");
t2.setName("线程二");
// 开启线程
t1.start();
t2.start();
}
}
方式三:利用Callable接口和Future接口方式实现
- 创建一个类MyCallable实现Callable接口
- 重写call(是有返回值的,表示多线程运行的结果)
- 创建MyCallable的对象(表示多线程要执行的任务)
- 创建FutureTask对象(作用管理多线程运行的结果)
- 创建Thread类的对象,并启动(表示线程)
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() {
// 求 1-100的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建了一个MyCallable的对象,表示多线程要执行的任务
MyCallable callable = new MyCallable();
// 创建FutureTask对象(作用管理多线程运行的结果)
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 创建线程的对象
Thread t1 = new Thread(futureTask);
// 启动线程
t1.start();
// 获取多线程运行的结果
Integer result = futureTask.get();
System.out.println(result);
}
}
thread中常见的成员方法:
-
String getName() 返回线程的名称
-
void setName(String name) 设置线程的名字(构造方法也可以设置名称)
细节:
1、如果我们没有给线程设置名字,线程也是默认有名字的 格式:Thread-X(X是序号,从0开始)
2、如果我们要给线程设置名称,可以用set 方法设置,也可以用构造方法设置 -
static Thread currentThread() 获取当前线程的对象
细节:
当JVM虚拟机启动之后,会自动的启动多线程,其中一条线程叫做main线程,他的作用就是调用main方法,并执行里面的代码,在以前我们写的所有代码,其实都在main线程中运行 -
static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
细节:
1、那条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
2、方法的参数:就表示睡眠的时间,单位毫秒,1秒=1000毫秒
3、当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
二、Thread状态
- New:新创建的线程,尚未执行;
- Runnable:运行中的线程,正在执行
run()
方法的Java代码; - Blocked:运行中的线程,因为某些操作被阻塞而挂起;
- Waiting:运行中的线程,因为某些操作在等待中;
- Timed Waiting:运行中的线程,因为执行
sleep()
方法正在计时等待; - Terminated:线程已终止,因为
run()
方法执行完毕。
图示如下:
┌─────────────┐
│ New │
└─────────────┘
│
▼
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
┌─────────────┐ ┌─────────────┐
││ Runnable │ │ Blocked ││
└─────────────┘ └─────────────┘
│┌─────────────┐ ┌─────────────┐│
│ Waiting │ │Timed Waiting│
│└─────────────┘ └─────────────┘│
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│
▼
┌─────────────┐
│ Terminated │
└─────────────┘
线程终止的原因是:
- 线程正常终止:
run()
方法执行到return
语句返回; - 线程意外终止:
run()
方法因为未捕获的异常导致线程终止; - 对某个线程的
Thread
实例调用stop()
方法强制终止(强烈不推荐使用)。
join():一个线程等待另一个线程,直到等待结束,可以指定等待时间,超过等待时间线程仍然没有结束就不再等待;
对已经运行结束的线程调用join()
方法会立刻返回。
interrupt() 中断线程,对线程的调用看她是否中断,isInterrupted()标示获取自身是否中断,如果目标线程处于等待状态,该线程会抛出异常InterruptedException,一般线程处于中断状态,应该立刻结束自身线程,线程间共享变量需要使用volatile
关键字标记,确保每个线程都能读取到更新后的变量值
三、异步ComletableFuture入门
- 分别是什么?然后如何使用?