开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
前言
虽然我工作中主要是编写 Go 语言,但是对于 Java 高并发相关的知识点,我还是时不时会温故下。今天,就一起来从 Java 的线程开始,对高并发编程有更加深刻的认识吧。
什么是线程?
在操作系统中,线程是能够独立运行的基本单位,也是CPU调度的基本单位。线程拥有一些在运行时需要用到的系统资源,例如程序计数器,寄存器和栈等。一个进程中会包含多个线程,而所有线程可以共享进程中的所有资源。
在 Java 中,实现线程的方式分为三种
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
我们一起看看代码。
继承 Thread 类
这种实现方式在我们日常开发中使用是比较常见的,简单来说就是定义一个继承 Thread 的类,并重写其 run() 方法:
public class ThreadLearning extends Thread {
@Override
public void run() {
// 业务逻辑
}
}
实现 Runnable 接口
这种实现方式在我们日常开发中也经常用到,它需要实现 Runnable 接口中的 run() 方法,跟继承 Thread 类差别不大:
public class RunnableLearning implements Runnable{
@Override
public void run() {
// 业务逻辑
}
}
实现 Callable 接口
上述两种实现方式有一定的局限性,我们看到 run() 方法的返回值都是 void,如果我们需要获取到线程执行时的返回值,那么我们就可以用实现 Callable 接口的方式来创建一个线程,并实现其中的 call() 方法:
public class CallableLearning implements Callable<String> {
@Override
public String call() throws Exception {
// 业务逻辑
return "业务逻辑返回值";
}
}
Callable 是一个泛型接口,线程的返回值类型是什么,那么 call() 方法的返回值就是什么。
线程的生命周期
一个线程的命周期需要经历多种不同的状态,从网上找到一张图,很好地概括了线程从创建到消亡的各个状态之间的变换:
如图所示,线程的各个状态为:
-
New:线程刚刚被初始化,但是还未调用 Tread.start() 方法
-
Runnable:线程调用了 start() 方法,进入可运行状态:
- Running:操作系统给线程分配了资源,开始调度线程,线程进入运行状态
- Ready:操作系统执行 yeild(),线程又由运行状态变为就绪状态
-
Blocked:线程未获取到锁,进入阻塞状态,直到其他线程释放锁
-
Waiting:等待状态,线程需要等待其他线程通知
-
Time Waiting:超时等待状态,线程等到一定的超时时间就会自行进入其他状态
-
Terminated:线程执行完毕,进入终止状态。