并发与并行
- 并发:指两个或多个事件在同一时间段内发生。
- 并行:指两个或多个事件在同一时刻发生(同时发生)。
进程与线程
-
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
-
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
-
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。


线程调度
- 分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
- 抢占式调度:优先让优先级高的銭程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
Java中的主线程
主线程:执行主(main)方法的线程。
单线程
单线程:Java程序中,只有一个线程,执行从main方法开始,从上到下的执行。
举例:
复制 | public class Student { |
| |
| public static void method1() { |
| for (int i = 0; i < 5; i++) { |
| System.out.println("我正在执行Student的方法1"); |
| } |
| } |
| |
| public static void method2() { |
| for (int i = 0; i < 5; i++) { |
| System.out.println("我正在执行Student的方法2"); |
| } |
| } |
| |
| public Student() { |
| } |
| |
| } |
复制 | public class Demo01MainThread { |
| public static void main(String[] args) { |
| Student.method1(); |
| Student.method2(); |
| } |
| } |
复制 | 控制台输出: |
| 我正在执行Student的方法1 |
| 我正在执行Student的方法1 |
| 我正在执行Student的方法1 |
| 我正在执行Student的方法1 |
| 我正在执行Student的方法1 |
| 我正在执行Student的方法2 |
| 我正在执行Student的方法2 |
| 我正在执行Student的方法2 |
| 我正在执行Student的方法2 |
| 我正在执行Student的方法2 |
从控制台输出可以知道,程序从上到下的执行,从方法1开始执行,到方法2开始执行。
多线程
创建多线程程序的第一种方式
创建Thread类的子类
java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类
实现步骤:
- 创建一个 Thread类的子类。
- 在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)。
- 创建Thread类的子类对象。
- 调用Thread类中的start方法,开启新的线程,执行run方法
void start()使该线程开始执行。Java虚拟机调用该线程的run方法。结果是两个线程并发地运行;当前线程(main线程)和另一个线程(创建的新线程,执行其run方法)。多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。Java程序属于抢占式调度,哪个线程的优先级高,哪个线程优先执行;同一个优先级,随机选择一个执行。
-
举例
复制 | public class Person extends Thread { |
| |
| |
| |
| |
| @Override |
| public void run() { |
| for (int i = 0; i < 6; i++) { |
| System.out.println("我正在执行重写的run方法中的线程:" + i); |
| } |
| } |
| |
| } |
复制 | public class Demo02MainThread { |
| public static void main(String[] args) { |
| |
| Thread myThread = new Person(); |
| |
| myThread.start(); |
| |
| |
| for (int i = 0; i < 6; i++) { |
| System.out.println("我正在执行main方法的线程:" + i); |
| } |
| |
| } |
| } |
-
控制台输出
复制 | 我正在执行main方法的线程:0 |
| 我正在执行main方法的线程:1 |
| 我正在执行重写的run方法中的线程:0 |
| 我正在执行main方法的线程:2 |
| 我正在执行重写的run方法中的线程:1 |
| 我正在执行重写的run方法中的线程:2 |
| 我正在执行重写的run方法中的线程:3 |
| 我正在执行重写的run方法中的线程:4 |
| 我正在执行重写的run方法中的线程:5 |
| 我正在执行main方法的线程:3 |
| 我正在执行main方法的线程:4 |
| 我正在执行main方法的线程:5 |
多线程的原理

Thread类的常用方法
复制 | public String getName() |
| |
| public void start() |
| |
| public void run() |
| |
| public static void sleep(long millis |
| // 返回对当前正在执行的线程对象的引用。 |
| |
getName()方法、start()方法、run()方法
复制 | public class MyThread extends Thread { |
| @Override |
| public void run() { |
| |
| } |
| } |
复制 | public class Demo01MyThread { |
| |
| public static void main(String[] args) { |
| |
| MyThread myThread1 = new MyThread(); |
| myThread1.start(); |
| String run1Name = myThread1.getName(); |
| |
| |
| MyThread myThread2 = new MyThread(); |
| myThread2.start(); |
| String run2Name = myThread2.getName(); |
| |
| MyThread myThread3 = new MyThread(); |
| myThread3.start(); |
| String run3Name = myThread3.getName(); |
| |
| System.out.println("线程1名称:" + run1Name); |
| System.out.println("线程2名称:" + run2Name); |
| System.out.println("线程3名称:" + run3Name); |
| } |
| |
| } |
复制 | 控制台输出: |
| 线程1名称:Thread-0 |
| 线程2名称:Thread-1 |
| 线程3名称:Thread-2 |
currentThread()方法
复制 | public class MyThread extends Thread { |
| |
| @Override |
| public void run() { |
| |
| System.out.println(Thread.currentThread()); |
| } |
| |
| } |
复制 | public class Demo02MyThread { |
| |
| public static void main(String[] args) { |
| MyThread myThread1 = new MyThread(); |
| myThread1.start(); |
| |
| MyThread myThread2 = new MyThread(); |
| myThread2.start(); |
| |
| MyThread myThread3 = new MyThread(); |
| myThread3.start(); |
| } |
| |
| } |
复制 | 控制台输出: |
| Thread[Thread-0,5,main] |
| Thread[Thread-2,5,main] |
| Thread[Thread-1,5,main] |
了解一下setName()方法
setName():设置线程的名称
复制 | public class Demo03MyThread { |
| public static void main(String[] args) { |
| MyThread myThread = new MyThread(); |
| myThread.setName("李华"); |
| myThread.start(); |
| } |
| } |
复制
sleep()方法
复制 | public class MyThread2 extends Thread { |
| @Override |
| public void run() { |
| |
| for (int i = 0; i < 11; i++) { |
| try { |
| |
| Thread.sleep(1000); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| System.out.print("第" + i + "秒 "); |
| } |
| } |
| } |
复制 | public class Demo01MyThread2 { |
| public static void main(String[] args) { |
| MyThread2 thread2 = new MyThread2(); |
| thread2.start(); |
| } |
| } |
复制 | 控制台输出: |
| 第0秒 第1秒 第2秒 第3秒 第4秒 第5秒 第6秒 第7秒 第8秒 第9秒 第10秒 |
创建多线程的第二种方式
实现Runnable接口,来创建多线程。
实现步骤
- 创建一个 Runnable接口的实现类。
- 在实现类中重写 Runnable接口的run方法,设置线程任务。
- 创建一个 Runnable接口的实现类对象。
- 创建Thread类对象,构造方法中传递 Runnable接口的实现类对象。
- 调用 Threads类中的 start方法,开启新的线程执行run方法
举例
复制 | |
| public class MyRunnable implements Runnable { |
| @Override |
| public void run() { |
| |
| for (int i = 0; i < 3; i++) { |
| System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); |
| } |
| } |
| } |
复制 | public class DemoRunnable { |
| public static void main(String[] args) { |
| |
| MyRunnable myRunnable = new MyRunnable(); |
| |
| |
| Thread thread = new Thread(myRunnable); |
| |
| |
| thread.start(); |
| |
| |
| for (int i = 0; i < 3; i++) { |
| System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); |
| } |
| } |
| } |
复制 | 控制台输出: |
| main ~~~~~~~~~ 0 |
| Thread-0 ~~~~~~~~~ 0 |
| main ~~~~~~~~~ 1 |
| Thread-0 ~~~~~~~~~ 1 |
| Thread-0 ~~~~~~~~~ 2 |
| main ~~~~~~~~~ 2 |
使用Runnable相比Thread有哪些优势
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避兔Java中的单继承的局限性。
- 増加程序的健壮性,实现解耦(把设置线程任务和开启线程分开)操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现 Runable或 Callable类线程,不能直接放入继承 Thread的类。
内部类实现创建多线程
复制 | public class MyRunnable implements Runnable { |
| @Override |
| public void run() { |
| |
| for (int i = 0; i < 3; i++) { |
| System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); |
| } |
| } |
| } |
复制 | public class DemoSimpleThread { |
| public static void main(String[] args) { |
| |
| MyRunnable myRunnable = new MyRunnable(); |
| |
| new Thread(myRunnable) { |
| @Override |
| public void run() { |
| System.out.print("匿名内部类的方式实现多线程的创建:"); |
| System.out.println(Thread.currentThread().getName() + "线程"); |
| } |
| }.start(); |
| |
| |
| System.out.println("main线程"); |
| } |
| } |
复制 | 控制台输出: |
| main线程 |
| 匿名内部类的方式实现多线程的创建:Thread-0线程 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)