Java多线程

Java多线程

程序、进程和线程

一、程序

  • 程序是存储在磁盘上, 包含可执行机器指令和数据的静态实体。 即进程或者任务是处于活动状态的计算机程序。

二、进程

  • 进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例,即运行中的程序。

  • 一个运行着的程序,可能有多个进程。进程在操作系统中执行特定的任务。

  • 程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。

三、 线程

  • 线程就是程序的执行路线,即进程内部的控制序列,或者说是进程的子任务。
  • 线程,轻量级,不拥有自己独立的内存资源,共享进程的代码区、数据区、堆区(注意没有栈区)、环境变量和命令行参数、文件描述符、信号处理函数、当前目录、用户ID和组ID等资源。
  • 线程拥有自己独立的栈,因此也有自己独立的局部变量。
  • 一个进程可以同时拥有多个线程,即同时被系统调度的多条执行路线,但至少要有一个主线程。

总结

  • 线程就是独立的执行路径;
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与
  • 操作系统紧密相关的,先后顺序是不能认为的干预的。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销。
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

线程实现

继承Thread类

线程是程序中执行的线程。Java虚拟机允许应用程序同时运行多个执行线程。

每个线程都有优先权。 具有较高优先级的线程优先于具有较低优先级的线程执行。 每个线程可能也可能不会被标记为守护进程。 当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护进程线程。

当Java虚拟机启动时,通常会有一个非守护进程线程(通常调用某个指定类的名为main的方法)。 Java虚拟机继续执行线程,直到发生以下任一情况:

  • 已调用类Runtimeexit方法,并且安全管理器已允许执行退出操作。
  • 通过调用run方法返回或抛出超出run方法传播的异常,所有非守护程序线程的线程都已死亡。

创建线程方式一:继承Thread类,重写run()方法,调用start()开启线程

public class MyThread extends Thread{
@Override
public void run() {
//子线程方法
for (int i = 0; i < 20; i++) {
System.out.println("我是子线程" + i);
}
}
public static void main(String[] args) {
//开启子线程
new MyThread().start();
for (int i = 0; i < 20; i++) {
System.out.println("我是主线程" + i);
}
}
}

执行结果

可以发现,主线程和子线程是”同时“进行的。

Thread类实现了Runnable接口,内部通过静态代理调用了run()方法

实现Runnable接口

public class MyThread implements Runnable{
@Override
public void run() {
//子线程方法
for (int i = 0; i < 20; i++) {
System.out.println("我是子线程" + i);
}
}
public static void main(String[] args) {
//创建线程对象,代理线程
new Thread(new MyThread()).start();
for (int i = 0; i < 20; i++) {
System.out.println("我是主线程" + i);
}
}
}

使用方法基本和继承Thread类相同,执行结果也相似。

实现Callable接口

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务: ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交执行: Future<Boolean> result1 = ser. submit(t1);
  • 获取结果: boolean r1 = result1.get()
  • 关闭服务: ser. shutdownNow();

示例代码

public class MyThread implements Callable<Boolean> {
@Override
public Boolean call() {
//子线程方法
System.out.println("执行了子线程");
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread t1 = new MyThread();
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(1);
//提交执行
Future<Boolean> result1 = ser.submit(t1);
//获取结果
boolean r1 = result1.get();
//关闭服务
ser. shutdownNow();
}
}

线程状态

线程同步

线程通信

posted @   超凡丶  阅读(111)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示