java-线程相关知识二

news2025/1/10 8:13:43

1. 线程基本方法

  • 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等。

1.1. 线程等待(wait)

  • 调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的是调用 wait()方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或同步代码块中。

1.2. 线程睡眠(sleep)

  • sleep 导致当前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的锁,sleep(long)会导致线程进入 TIMED-WATING 状态,而 wait()方法会导致当前线程进入 WATING 状态

1.3. 线程让步(yield)

  • yield 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片。一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感。

1.4. 线程中断(interrupt)

  • 中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位。这个线程本身并不会因此而改变状态(如阻塞,终止等)。
  1. 调用 interrupt()方法并不会中断一个正在运行的线程。也就是说处于 Running 状态的线程并不会因为被中断而被终止,仅仅改变了内部维护的中断标识位而已。
  2. 若调用 sleep()而使线程处于 TIMED-WATING 状态,这时调用 interrupt()方法,会抛出InterruptedException,从而使线程提前结束 TIMED-WATING 状态。
  3. 许多声明抛出 InterruptedException 的方法(如 Thread.sleep(long mills 方法)),抛出异常前,都会清除中断标识位,所以抛出异常后,调用 isInterrupted()方法将会返回 false。
  4. 中断状态是线程固有的一个标识位,可以通过此标识位安全的终止线程。比如,你想终止一个线程 thread 的时候,可以调用 thread.interrupt()方法,在线程的 run 方法内部可以根据 thread.isInterrupted()的值来优雅的终止线程。

1.5. Join 等待其他线程终止

  • join() 方法,等待其他线程终止,在当前线程中调用一个线程的 join() 方法,则当前线程转为阻塞
    状态,回到另一个线程结束,当前线程再由阻塞状态变为就绪状态,等待 cpu 的宠幸。

1.6. 为什么要用 join()方法?

  • 很多情况下,主线程生成并启动了子线程,需要用到子线程返回的结果,也就是需要主线程需要在子线程结束后再结束,这时候就要用到 join() 方法。
System.out.println(Thread.currentThread().getName() + "线程运行开始!");
Thread6 thread1 = new Thread6();
thread1.setName("线程 B");
thread1.join();
System.out.println("这时 thread1 执行完毕之后才能执行主线程");

1.7. 线程唤醒(notify)

  • Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意的,并在对实现做出决定时发生,线程通过调用其中一个 wait() 方法,在对象的监视器上等待,直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。类似的方法还有 notifyAll() ,唤醒再次监视器上等待的所有线程。

1.8. 其他方法:

  1. sleep():强迫一个线程睡眠N毫秒。

  2. isAlive(): 判断一个线程是否存活。

  3. join(): 等待线程终止。

  4. activeCount(): 程序中活跃的线程数。

  5. enumerate(): 枚举程序中的线程。

  6. currentThread(): 得到当前线程。

  7. isDaemon(): 一个线程是否为守护线程。

  8. setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束)

  9. setName(): 为线程设置一个名称。

  10. wait(): 强迫一个线程等待。

  11. notify(): 通知一个线程继续运行。

  12. setPriority(): 设置一个线程的优先级。

  13. getPriority()::获得一个线程的优先级。

2. 线程上下文切换

  • 巧妙地利用了时间片轮转的方式, CPU 给每个任务都服务一定的时间,然后把当前任务的状态保存下来,在加载下一任务的状态后,继续服务下一任务,任务的状态保存及再加载, 这段过程就叫做上下文切换。时间片轮转的方式使多个任务在同一颗 CPU 上执行变成了可能。

2.1. 进程

  • (有时候也称做任务)是指一个程序运行的实例。在 Linux 系统中,线程就是能并行运行并且与他们的父进程(创建他们的进程)共享同一地址空间(一段内存区域)和其他资源的轻量级的进程。

2.2. 上下文

  • 是指某一时间点 CPU 寄存器和程序计数器的内容。

2.3. 寄存器

  • 是 CPU 内部的数量较少但是速度很快的内存(与之对应的是 CPU 外部相对较慢的 RAM 主内存)。寄存器通过对常用值(通常是运算的中间值)的快速访问来提高计算机程序运行的速度。

2.4. 程序计数器

  • 是一个专用的寄存器,用于表明指令序列中 CPU 正在执行的位置,存的值为正在执行的指令的位置或者下一个将要被执行的指令的位置,具体依赖于特定的系统。

2.5. PCB-“切换桢”

  • 上下文切换可以认为是内核(操作系统的核心)在 CPU 上对于进程(包括线程)进行切换,上下文切换过程中的信息是保存在进程控制块(PCB, process control block)中的。PCB 还经常被称作“切换桢”(switchframe)。信息会一直保存到 CPU 的内存中,直到他们被再次使用。

2.6. 上下文切换的活动:

  1. 挂起一个进程,将这个进程在 CPU 中的状态(上下文)存储于内存中的某处。
  2. 在内存中检索下一个进程的上下文并将其在 CPU 的寄存器中恢复。
  3. 跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行),以恢复该进程在程序中。

2.7. 引起线程上下文切换的原因

  1. 当前执行任务的时间片用完之后,系统 CPU 正常调度下一个任务;
  2. 当前执行任务碰到 IO 阻塞,调度器将此任务挂起,继续下一任务;
  3. 多个任务抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,继续下一任务;
  4. 用户代码挂起当前任务,让出 CPU 时间;
  5. 硬件中断;

3. 同步锁与死锁

3.1. 同步锁

  • 当多个线程同时访问同一个数据时,很容易出现问题。为了避免这种情况出现,我们要保证线程同步互斥,就是指并发执行的多个线程,在同一时间内只允许一个线程访问共享数据。 Java 中可以使用 synchronized 关键字来取得一个对象的同步锁。

3.2. 死锁

何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

4. 线程池原理

  • 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。

4.1. 线程复用

  • 每一个 Thread 的类都有一个 start 方法。 当调用 start 启动线程时 Java 虚拟机会调用该类的 run方法。 那么该类的 run() 方法中就是调用了 Runnable 对象的 run() 方法。 我们可以继承重写Thread 类,在其 start 方法中添加不断循环调用传递过来的 Runnable 对象。 这就是线程池的实现原理。循环方法中不断获取 Runnable 是用 Queue 实现的,在获取下一个 Runnable 之前可以是阻塞的。

4.2. 线程池的组成

  • 一般的线程池主要分为以下 4 个组成部分:
  1. 线程池管理器:用于创建并管理线程池
  2. 工作线程:线程池中的线程
  3. 任务接口:每个任务必须实现的接口,用于工作线程调度其运行
  4. 任务队列:用于存放待处理的任务,提供一种缓冲机制
  • Java 中 的 线 程 池 是 通 过 Executor 框 架 实 现 的 , 该 框 架 中 用 到 了 Executor , Executors ,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask 这几个类。
    *

ThreadPoolExecutor 的构造方法如下:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
  1. corePoolSize:指定了线程池中的线程数量。
  2. maximumPoolSize:指定了线程池中的最大线程数量。
  3. keepAliveTime:当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多次时间内会被销毁。
  4. unit:keepAliveTime 的单位。
  5. workQueue:任务队列,被提交但尚未被执行的任务。
  6. threadFactory:线程工厂,用于创建线程,一般用默认的即可。
  7. handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。

4.3. 拒绝策略

  • 线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。
  • JDK 内置的拒绝策略如下:
    1. AbortPolicy : 直接抛出异常,阻止系统正常运行。
    2. CallerRunsPolicy : 只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。
    3. DiscardOldestPolicy : 丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。
    4. DiscardPolicy : 该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这是最好的一种方案。
  • 以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler 接口。

4.4. Java 线程池工作过程

  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
  2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
    a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
    b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
    c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
    d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常 RejectExecutionException。
  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
  4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/916207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA配置文件乱码

一、问题描述 导入项目后&#xff0c;发现配置文件乱码了&#xff0c;但是程序运行还能正常使用。 不过&#xff0c;配置文件乱码&#xff0c;对代码开发还是很有阻碍。还是需要去解决。 二、解决方案 在Idea中设置默认编码方式&#xff0c;可以保证新建的文件使用正确的编码…

制图成本降低80%,百度如何打造轻地图?

作者|HiEV 编辑|张祥威 编者注&#xff1a; 本文是HiEV出品的系列直播「智驾地图之变」第一期问答环节内容整理。百度智驾地图业务部主任架构师万聪与连线嘉宾鉴智机器人技术副总裁潘屹峰、领骏科技研发副总裁严晗、主持嘉宾周琳展开深度交流&#xff0c;并进行了答疑。 本期…

安装docker服务,配置镜像加速器

文章目录 1.安装docker服务&#xff0c;配置镜像加速器2.下载系统镜像&#xff08;Ubuntu、 centos&#xff09;3.基于下载的镜像创建两个容器 &#xff08;容器名一个为自己名字全拼&#xff0c;一个为首名字字母&#xff09;4.容器的启动、 停止及重启操作5.怎么查看正在运行…

亿邦智库《2023数字化采购发展报告》解读,企企通推动企业采购数字化及供应链协同智能化发展

采购成本是企业成本控制的主体和核心。在当前供应链的背景下&#xff0c;采购数字化一方面可以通过提高效率来降低成本&#xff0c;增强合作和风险缓解能力&#xff1b;另一方面&#xff0c;信息、物流和资本流动的整合和重建将提高供应链的灵活性和灵活性&#xff0c;增强面向…

Spring Framework核心模块

core Spring Core是Spring框架的基础API核心模块&#xff0c;提供了基本的IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;和DI&#xff08;Dependency Injection&#xff0c;依赖注入&#xff09;功能。 core核心功能举例 资源管理-系统资源加载 Fi…

Qwen-7B微调实例

Qwen-SFT 阿里通义千问(Qwen-7B-Chat/Qwen-7B), 微调/LORA/推理 踩坑 1. tokenizer.encode输出(不会新增特殊字符), 为 [真实文本tokens]: 2. chat-PROMPT: <|im_start|>system\nYou are a helpful assistant.<|im_end|>\n<|im_start|>user\n你好<|im…

vue3移动h5调试插件

下载插件 pnpm i vconsole代码部分 main.ts中加入如下代码 import VConsole from vconsole;const isPc () > {const userAgentInfo navigator.userAgent;const Agents ["Android", "iPhone","SymbianOS", "Windows Phone",&q…

数据结构与算法:通往编程高地的必修课(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

行为型(十一) - 中介模式

一、概念 中介模式&#xff08;Mediator Pattern&#xff09;&#xff1a;中介模式定义了一个单独的&#xff08;中介&#xff09;对象&#xff0c;来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互&#xff0c;来避免对象之间的直接交互。 二、实现 借…

生信豆芽菜-缺氧评分的计算

网址&#xff1a;http://www.sxdyc.com/gradeHypoxia 1、数据准备 表达谱数据&#xff0c;行为基因&#xff0c;列为样本 2、提交后&#xff0c;等待运行成功即可下载 当然&#xff0c;如果不清楚数据是什么样的&#xff0c;可以选择下载我们的示例数据&#xff0c;也可以…

VBA Excel函数的使用

一个简单的教程&#xff0c;实现VBA自定义函数。 新建模块 复制后面的代码放进来 函数的入口参数不定义&#xff0c;则认为是一块区域&#xff1b; 反之&#xff0c;如FindChar1 As String&#xff0c;则认为是输入的单值。 循环和分支如下例子&#xff0c;VB比较接近自然语…

纯手写Tomcat,看不懂你来揍我【附源码、图文详解】

源码放在了文章末尾 理论知识 何为Tomcat Tomcat是一个开源的Servlet容器&#xff0c;它实现了Java Servlet、JavaServer Pages (JSP)、WebSocket等Java EE规范&#xff0c;用于在Web服务器上运行Java Web应用程序。 说的简单点&#xff0c;Tomcat能处理网络传输来的请求。 …

Linux内核提权漏洞

Linux内核提权漏洞 漏洞名称&#xff1a;脏牛&#xff08;Dirty COW&#xff09;CVE-2016-5195 漏洞危害&#xff1a;低权限用户利用该漏洞技术可以在全版本 Linux 系统上实现本地提权 影响范围&#xff1a;Linux 内核2.6.22 < 3.9 (x86/x64) 攻击机&#xff1a;Kali Linu…

Vmware 虚拟机挂起恢复后发现无法 Ping 通,无法连接到主机

解决办法 进入对应主机中&#xff0c;切换到 root 账户&#xff0c;重启网络服务。 systemctl stop NetworkManager systemctl restart network在网上还找到了另一种解决方法&#xff1a; 在网卡配置文件中增加参数 NM_CONTROLLED"no"。 在 Centos 7 中修改如下所…

Elasticsearch配置优化

以下的优化基础是安装的 Elasticsearch 版本为 7.17.7&#xff0c;同时jdk版本为 1.8.321 1、jvm参数优化 这里说的jvm参数调优&#xff0c;是指elasticsearch安装目录下的jvm.options配置&#xff0c;如下图所示&#xff1a; 这里调整的内容主要是调整垃圾回收的收集器&#…

打造引人注目的直播体验:直播美颜SDK的集成与优化

随着移动互联网的迅速发展&#xff0c;视频直播已经成为人们交流、娱乐和信息传递的重要方式。在这个多元化的直播市场中&#xff0c;吸引观众的注意力变得尤为重要。其中&#xff0c;美颜技术在增强直播体验方面发挥着关键作用。直播美颜SDK的集成和优化使得主播能够以最佳状态…

Docker安装并配置cAdvisor

Linux下安装Docker请参考&#xff1a;Linux安装Docker 简介 cAdvisor 是 Google 开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行 CAdvisor 用户可以轻松的获取到当前主机上容器的运行统计信息&#xff0c;并以图表的形式向用户展示。 cAdvisor 可以对…

问道管理:煤炭板块发力拉升,陕西黑猫涨停,郑州煤电等走高

煤炭板块23日盘中发力拉升&#xff0c;截至发稿&#xff0c;陕西黑猫涨停&#xff0c;郑州煤电涨近6%&#xff0c;平煤股份、兰花科创、兖矿能源涨近3%&#xff0c;山西焦煤、潞安环能、我国神华等均走高。 关于该板块&#xff0c;国信证券表明&#xff0c;展望下半年&#xff…

IC芯片 trustzone学习

搭建Airplay TA环境需要在IC的TrustZone中进行。TrustZone是一种安全技术&#xff0c;用于隔离安全和非安全环境&#xff0c;并保护敏感文件。在TrustZone中&#xff0c;我们需要编写一个叫做TA&#xff08;Trusted Application&#xff09;的应用程序来控制这些私密文档。 &am…

echart 图表添加数据分析功能,(右上控制选择)

echart 图表添加数据分析功能,可区域选择数据,右上按钮,控制echart行为 chart.on(globalcursortaken, onGlobalcursortaken); //绑定事件chart.off("brushSelected");//解绑事件处理函数chart.on(brushSelected, renderBrushed);getBarDev2(eIndex, eTimeArr, eSerie…