1. 前言
线程是处理器的基本调度单位,是比进程更轻量级的调度单位。线程的引入可以把一个进程的资源分配和执行调度区分开,线程间可以共享进程资源,又可以独立调度。
Java 线程类在线文档:https://docs.oracle.com/en/java/javase/15/docs/api/
我一看是 JDK15,啪的一下点进来了,很快啊。欸,不消费马老师了,看着正在跑项目的 JDK8,我的眼角湿润了
2. 实现线程的三种方式
2.1 实现线程的三种方式
- 使用内核线程实现
- 使用用户线程实现
- 用户线程+轻量级进程混合实现
2.2 用户线程+轻量级进程混合实现介绍
- 内核线程(KLT,Kernel-Level Thread)
直接由操作系统内核(Kernel)支持的线程。 - 轻量级进程(LWP,Light Weight Process)
轻量级进程是我们通常意义上所讲的线程,是基于内核线程的一种高级接口,程序一般不直接使用内核线程,使用轻量级进程。 - 用户线程(UT,User Thread)
不是内核线程的线程可以看作为用户线程。
内核线程由内核完成线程切换,内核通过线程调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。
每个轻量级进程都由一个内核线程支持,是轻量级线程和内核线程一对一的线程模型。所以轻量级进程是存在受限于内核线程的,内核资源有限,支持的轻量级进程也是有限。一个程序进程需要多个轻量级线程支持,这种线程模型受内核资源限制比较大。
用户线程和建立、同步、消费、调度不需要内核的帮助,是快速且低耗的,支持更大规模的线程数量。进程与用户线程的关系属于一对多的线程模型。用户线程没有内核的支援,需要解决线程调度,阻塞等问题,比较复杂,这种仅使用用户线程的线程模型也渐渐被弃用。
用户线程和轻量级进程混合实现,两者之间的关系为 N:M,这种关系属于多对多的线程模型.
2.3 线程调度的两种模式
线程调度指系统为线程分配处理器使用权的过程。
- 协同式线程调度
实现简单,线程执行完成主动通知系统进行线程切换;线程执行时间系统不可控,如果线程阻塞,则会一直占用处理器资源。 - 抢占式线程调度
交由系统分配时间,线程切换可由程序进行控制,比如 Java 的 Thread.yeild() 线程让步方法。线程执行时间系统可控。
3. Java 中的线程调度及状态
3.1 Java 中的线程调度
是抢占式调度,支持线程优先级,优先级高的更容易被先执行;支持线程让步等
3.2 Thread 线程对象的状态
- 新建(New)
创建后且未调用 start() 方法启动线程的初始状态 - 运行(Runnable)
Java 中的运行状态包括操作系统线程状态中的 Runnable 和 Ready;即 Java 中的运行状态包含,线程正在运行或者线程准备状态下正在等待分配处理器资源。 - 无限期等待(Waiting)
处于无限期等待的线程,不会被分配处理器资源去执行,需要等待其他线程显式的去唤醒。
Object.wait()、Thread.join()、LockSupport.park()
方法可使线程进入无限期等待状态。 - 限期等待(Timed Waiting)
该状态下,线程也不会被分配处理器资源,但是可以不需要其他线程显式唤醒,当前线程一段时间(时间大小可自定义)后会由系统自动唤醒。
Thread.sleep(timeOut)、Object.wait(timeOut)、Thread.join(timeOut)、LockSupport.parkNanos()、LockSupport.parkUntil()
方法可使得线程进入限期等待状态。 - 阻塞(Blocked)
线程阻塞,需要等待获取到一个排他锁,这个事件将在另一个线程放弃这个排他锁时发生。 - 结束(Terminated)
线程执行结束,或者已终止的线程
阻塞状态与等待状态的区别
等待线程,需要其他线程来唤醒,或者一定等待期限后由系统唤醒进入运行状态。阻塞状态需要获取其他线程释放被占用的排他锁才可进入运行状态。
4. Thread 线程类的构造方法
4.1 演示代码
/**
* @className: ThreadConstructor
* @description: Thread Constructor
**/
public class ThreadConstructor {
public static void main(String[] args) {
init();
}
private static void init() {
// target runnable
final Runnable targetRunnable = new Runnable() {
@Override
public void run() {
// to do something
}
};
// mainThread's threadGroup;
final ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();
final String thread_04Name = "Thread-Constructor-04";
final String thread_05Name = "Thread-Constructor-05";
final String thread_06Name = "Thread-Constructor-06";
final String thread_07Name = "Thread-Constructor-07";
final String thread_08Name = "Thread-Constructor-08";
// init stack size, Beyond method stack throw java.lang.StackOverflowError
long stackSize = 1 << 24;
Thread thread_01 = new Thread();
Thread thread_02 = new Thread(targetRunnable);
Thread thread_03 = new Thread(mainThreadGroup, targetRunnable);
Thread thread_04 = new Thread(thread_04Name);
Thread thread_05 = new Thread(mainThreadGroup, thread_05Name);
Thread thread_06 = new Thread(targetRunnable, thread_06Name);
Thread thread_07 = new Thread(mainThreadGroup, targetRunnable, thread_07Name);
Thread thread_08 = new Thread(mainThreadGroup, targetRunnable, thread_08Name, stackSize);
thread_01.start();
thread_02.start();
thread_03.start();
thread_04.start();
thread_05.start();
thread_06.start();
thread_07.start();
thread_08.start();
mainThreadGroup.list();
}
}
4.2 入参说明
- targetRunnable
是接口 Runnable 的实现,需要实现 run() 方法。线程交由 JVM 管理,线程启动后,可运行的线程会执行 run() 的内部逻辑。 - threadGroup
线程组,用来管理线程的,由线程组成;线程对象创建时可指定所属线程组 threadGroup; 未指定线程组则为 null - name
线程名称,默认名称为 Thread-index,index 属于[0, +∞)。线程名称支持自定义,允许重复,不可为空;线程 ID 自增唯一。 - stackSize
指定方法栈大小,避免内存泄漏。超出指定大小则会抛出 java.lang.StackOverflowError
关键代码演示:
private static long threadSeqNumber;
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
// ... ...
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
// ... ...
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
/* Set thread ID */
tid = nextThreadID();
}
5. Thread 线程的两种实现方式
5.1 作为子类继承 Thread 类
class ThreadByExtendsThread extends Thread {
@Override
public void run() {
// super.run() or custom to do something
super.run();
}
}
eg: 线程调用方式
ThreadByExtendsThread thread = new ThreadByExtendsThread();
thread.start();
5.2 作为实现类实现 Runnable 接口
class ThreadByImplementsRunnable implements Runnable {
@Override
public void run() {
// custom to to something
}
}
eg: 线程调用方式
ThreadByImplementsRunnable runnable = new ThreadByImplementsRunnable();
Thread thread = new Thread(runnable);
thread.start();
Power By niaonao