1950年代,计算机系统通常是单任务的。早期计算机一次只能执行一个程序,需要人工切换。这种设计简单但效率低下1960年代,多任务系统的概念开始萌芽。早期的大型机操作系统如IBM的OS/360引入了分时技术,允许多个用户同时使用计算机资源。虽然计算机实际一次只能干一件事,但靠这种“闪电式切换”,用户感觉电脑在同时处理多个任务1970年代,Unix操作系统诞生,采用了多任务设计。Unix通过进程调度和时间片轮转机制,允许多个程序并发执行。这一设计成为现代多任务系统的基础
单任务(进程)系统:同一时间只能运行一个程序或任务,任务必须按顺序完成。用户需等待当前任务结束后才能启动新任务。系统资源由一个任务独占,缺乏并发能力,适用于简单应用场景
多任务(进程)系统:允许同时运行多个程序或任务,通过时间片轮转或优先级调度实现并发
进程(Process)/任务(Task):进程是计算机中正在运行的程序的实例(应用程序与进程的关系近似于Java中类和对象的关),是操作系统进行资源分配的基本单位
打开任务管理器,这里显示的每一个运行中的exe(可执行文件),就叫做进程

当一个进程被创建的时候,操作系统会为它创建一个/多个PCB(Process Control Block进程控制块),类似C语言的结构体/Java中的类,PCB里面会存放该进程的各种属性



优点:
缺点:

线程(Thread)/轻量级进程:由操作系统调度,不用额外分配资源,是操作系统调度执行的基本单位。一个进程可以包含多个线程,所有线程共享进程的资源(由线程控制块TCB管理),但每个线程拥有独立的执行栈和程序计数器
优点:
缺点:
构造方法如下:

1.直接继承Thread类
优点:
缺点:
//Thread类实现了Runnable接口,所以需要重写run方法
class MyThread extends Thread{
@Override
public void run() {
while (true) {
System.out.println("Hello MyThread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new MyThread();
//启动线程
thread.start();
}
}2.实现Runnable接口
优点:
缺点:
class MyRunnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("Hello MyRunnable");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
//启动线程
thread.start();
}
}3.匿名内部类创建Runnable子类对象
优点:
缺点:
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(){
//匿名内部类
@Override
public void run() {
while (true) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
thread.start();
}4.lambda表达式创建Runnable子类对象
优点:
缺点:
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (true){
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
}
}public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(()->{});
//获取线程id
System.out.println(thread.getId());
//获取线程name
System.out.println(thread.getName());
}
}public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
//false,线程还没启动
System.out.println(thread.isAlive());
thread.start();
//true,线程正在执行任务
System.out.println(thread.isAlive());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//false,线程结束
System.out.println(thread.isAlive());
}
}
前台线程:会阻止进程终止,即使主线程执行完毕,只要存在前台线程仍在运行,进程会继续运行直到所有前台线程完成任务。默认情况下,主线程是前台线程,通过Thread类创建的线程默认也是前台线程后台线程:不会阻止进程终止,当所有前台线程结束时,后台线程会被自动终止,无论是否完成任务
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while (true) {
try {
Thread.sleep(1000);
System.out.println("Hello Thread");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//把thread设置为后台线程,不会阻止主线程的结束,thread线程会伴随main线程的结束而结束
thread.setDaemon(true);
thread.start();
System.out.println("Hello Main");
}
}
运行结果:Hello Main
start方法:用于启动一个新线程,新线程会执行run方法中的代码。每个线程只能调用一次start,重复调用会抛出IllegalThreadStateException(无论该线程是否执行完任务)
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println("Hello Thread");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//开启新线程,thread线程执行run方法
thread.start();
for (int i = 0; i < 5; i++) {
System.out.println("Hello Main");
Thread.sleep(100);
}
}
}
run方法:直接调用run方法不会创建新线程,而是在当前线程中执行run方法的代码
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println("Hello Thread");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//main线程执行run方法
thread.run();
for (int i = 0; i < 5; i++) {
System.out.println("Hello Main");
Thread.sleep(100);
}
}
}
Thread.sleep:是Java中用于暂停当前线程执行的一个静态方法。它允许线程在指定的时间内进入休眠状态,期间不会占用CPU资源。休眠结束后,线程会重新进入就绪(RUNNABLE)状态,等待调度执行
//毫秒级精确度
//需要处理InterruptedException(编译时异常)
public static native void sleep(long millis)
throws InterruptedException;
//纳秒级精确度
public static void sleep(long millis, int nanos)
throws InterruptedException
知识回顾:

在继承Thread 类的自定义线程类中,可以通过this关键字直接访问当前线程的属性和方法
class MyThread extends Thread{
@Override
public void run() {
System.out.println(this.getId() + " " + this.getName());
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}在使用Runnable接口或Lambda表达式创建线程时,无法直接使用this获取线程信息,因为this指向的是Runnable实例而非线程对象。应调用 Thread.currentThread()获取当前线程的引用
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
Thread t1 = Thread.currentThread();
System.out.println(t1.getId()+ " " + t1.getName());
});
thread.start();
}
}1.Java的线程模型:栈帧中的局部变量是线程私有的,这意味着每个线程都有自己的栈帧,局部变量存储在栈帧中,一个线程不得访问另一个线程中的局部变量2.变量捕获(Variable Capture):通常与Lambda表达式和匿名内部类相关,允许捕获外部作用域的变量,但这些变量必须是final修饰或事实final结合以上两点,变量捕获机制允许一个线程获取另一个线程中的final变量

在上述代码中,thread线程捕获到main线程中的isQuit变量,本质上是将isQuit变量拷贝到thread线程中,而不是直接访问main的栈帧(避免因变量的生命周期而可能产生的线程安全问题)
如果允许匿名内部类或lambda表达式访问并修改局部变量,就会导致变量逃逸(escape),即变量的引用或值被传递到栈帧之外造成栈中变量的内存地址泄漏,这种情况会引发严重的安全问题,因为原本被Java线程模型规定为线程私有的数据可能会被并发访问
通过修改类变量来终止线程
缺点:
public class ThreadDemo {
public static boolean isQuit = false;
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (!isQuit){
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Over Thread");
});
thread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
isQuit = true;
}
}
interrupt():是 Java中用于中断线程的方法。它的核心作用是向目标线程发送一个中断信号,但并不会直接终止线程的执行。需要主动检查中断状态并决定如何响应中断
public class TreadDemo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
System.out.println("Over Thread");
});
thread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//终止线程,并唤醒线程中的sleep
thread.interrupt();
}
}
join方法:用于等待线程执行完成。调用某个线程的join方法后,当前线程会被阻塞,直到目标线程执行完毕
方法 | 说明 |
|---|---|
join() | 等待线程无限期执行完成 |
join(long millis) | 等待线程执行完成,但最多等待millis毫秒 |
join(long millis, int nanos) | 等待线程执行完成,但最多等待millis毫秒+nanos纳秒 |
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0;i < 3;i++){
System.out.println("Hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Over Thread");
});
thread.start();
//main等待thread线程执行完毕
thread.join();
//main线程恢复执行
System.out.println("Hello Main");
}
}
执行结果:Hello Thread Hello Thread Hello Thread Over Thread Hello Main