1-线程的创建以及运行
什么是线程
- 进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程则是进行的一个执行路径一个进程中至少含有一个线程,进程中的多个线程共享进程的资源。
- 操作系统在分配资源的时候是把资源分配给进程的,但是CPU资源比较特殊,它是分配给线程的,因此真正要占用CPU资源的是线程,线程是CPU分配的基本单位。
- 在java中,启动main函数其实就是启动了一个JVM进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程。
- 进程和线程的关系如图所示:
- 如图:每一个进程会有若干个线程,多个线程之间共享进程中的堆和方法区资源。但是每个线程都有自己的程序计数器金和栈区。
- 程序计数器是一块内存区域,用来记录当前要执行指令的地址,那么为何要将程序计数器设为私有的呢?原因是线程才是CPU执行的基本单位,而CPU一般使用的是时间片轮转的方式让线程轮询占用。所以当前线程CPU时间片用完后,就要让出CPU,等下次轮到自己的时候再执行。这就需要程序计数器记录当前CPU执行到哪里了,下一步该执行的指令地址是什么,等下次该线程再次分配到CPU时间片之后就可以从私有的程序计数器中读取并继续执行。
- 每个线程都有自己的栈资源,用于存储该线程的局部变量,这些局部变量是线程私有的,其他线程所不能访问的。
- 堆是一个进程中最大的一块内存,堆倍进程中的所有线程都是共享的,是创建进程的时候分配的,堆里面主要存放的是new操作创建的对象实例。
- 方法区用来存放的是JVM加载的类,常量以及静态变量等信息,也是线程共享的。
线程创建与运行
-
java中有三种创建线程的方式
-
- 实现Runnable接口的run方法 没有返回值
- 继承Threag类并重写run方法 没有返回值
- 使用FutureTask方式 有返回值
-
-
继承Thread方法
-
package com.heiye.learn1; public class ThreadTest { //继承Thread类并重写run方法 public static class MyThread extends Thread { @Override public void run() { System.out.println("I am a child thread"); } } public static void main(String[] args) { //创建一个线程 MyThread myThread = new MyThread(); //启动线程 myThread.start(); } }
-
上图中的MyThread类继承了Thread类,并重写了run方法。在main函数里创建了一个MyThread实例,然后调用该实例的start()方法启动了线程。当创建完thread对象后该线程并没有立刻执行,直到调用了start()方法后就算真正的启动了线程,但是并没有立刻执行而是处于就续状态,这个就绪状态指的是该线程已经获取到了除CPU以外的资源,等待获取到CPU资源后才会真正的处于运行状态,一旦run方法执行完毕后,该线程就会处于终止状态。
-
-
实现Runnable接口的run方法
-
package com.heiye.learn1; public class RunnableTask implements Runnable{ @Override public void run() { System.out.println("I am child thread"); } public static void main(String[] args) { RunnableTask task=new RunnableTask(); new Thread((task)).start(); } }
-
-
使用FutureTask方法
-
package com.heiye.learn1; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallerTask implements Callable<String> { @Override public String call() throws Exception { return "hello"; } public static void main(String[] args) { //创建异步任务 FutureTask<String> futureTask = new FutureTask<>(new CallerTask()); //启动线程 new Thread(futureTask).start(); try { //等待执行结束后返回结果 String result = futureTask.get(); System.out.println(result); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } } }
-
CallerTask类实现了Callable接口的call()方法,在main函数中创建了一个FutureTask对象,构造函数为CallerTask实例,然后使用FutureTask对象作为任务创建一个线程并启动它,最后通过futureTask的get()方法获取到线程执行完后返回的结果。
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构