并发编程线程基础

本文详细介绍了线程的概念、创建与运行方式、线程间同步机制如等待与通知等,并探讨了线程上下文切换、死锁避免策略及守护线程的作用。此外还深入解析了ThreadLocal的工作原理。

一、什么是线程

线程是进程的一个实体,线程本身不会单独存在。进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈区域。

二、线程的创建与运行

  • 继承Thread类,重写run方法
  • 实现Runnable接口中的run方法
  • 实现Callable中的call方法(含返回值,通过FutureTask实现)

使用继承的优缺点

  • 优点:在run方法中直接使用this可以获取当前线程。
  • 缺点:Java不支持多继承;任务和代码没有分离,当多个线程执行一样的任务的时候,需要多份任务代码

三、线程等待与通知

  • wait():调用线程被阻塞挂起,直到发生notify()或者notifyAll()或者调用了该线程的interrupt()方法抛出InterruptedException异常才会被返回。如果调用wait()方法的线程没有事先获取该对象的监视器锁,则调用wait方法的线程会抛出IllegalMonitorStateException异常。
  • wait(long timeout):如果一个线程调用共享对象的该方法挂起后,没有在指定的timeout ms时间内被其他线程调用该共享变量的notify()或者notifyAll()方法唤醒,那么该函数还是会因为超时而返回。
  • wait(long timeout, int nanos):内部调用的是wait(long timeout),只有的当nanos>0时才会让timeout递增1。
  • notify():随机唤醒一个在该变量上调用wait系列方法后被挂起的线程,被唤醒后不能马上从wait方法返回并继续执行,必须获取了共享对象的监视器锁后才可以返回。
  • notifyAll():唤醒所有在该变量上调用的wait系列方法而被挂起的线程。

四、等待线程执行终止的join方法

join是Thread类直接提供的,join是无参且返回值为的void方法。假设线程A调用了线程B的join方法后被阻塞,当其他线程调用了线程A的interrupt方法中断了线程A时,线程A会抛出InterruptedException。

五、让线程睡眠的sleep方法

Thread类中有一个静态的sleep方法,当一个执行中的线程调用了Thread的sleep方法后,调用线程会暂时让出指定时间的执行权,也就是这期间不参与cpu的调度,但是该线程所拥有的监视器资源还是持有不让出的。如果睡眠期间,其他线程调用了该线程的interrupt()方法中断了该线程,则该线程会在调用sleep方法的地方抛出InterruptedException异常而返回。

六、让出CPU执行权的yield方法

Thread类中有一个静态的yield方法,当一个线程调用yield方法时,实际就是暗示线程调度器当前线程请求让出自己的cpu使用,但是线程调度器可以无条件忽视这个暗示。
sleep和yield方法的区别在于,当线程调用sleep方法时调用线程会被阻塞挂起指定的时间,在这期间线程调度器不会去调度该线程。而调用yield方法时,线程只是让出自己剩余的时间片,并没有被阻塞挂起,而是处于就绪状态,线程下一轮调度时就有可能调度到当前线程执行。

七、线程中断

Java中的线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理。

  • void interrupt()方法:中断实现,设置中断标志为true并立即返回。
  • boolean isInterrupted()方法:检测当前线程是否被中断,如果是返回true,否则返回false。
  • boolean interrupted()方法:检测当前线程是否被中断,如果是返回true,否则返回false,该方法如果发现当前线程被终端,则会清除中断标志,并且该方法时static,可以通关Thread类直接调用。

八、理解线程上下文切换

上下文:线程的执行现场,当再次执行时根据保存的执行现场信息恢复执行现场。
线程上下文切换的时机

  • 当前线程的CPU时间片使用完处于就绪状态
  • 当前线程被其他线程中断时

九、线程死锁

什么是线程死锁?

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续下去。
死锁的条件

  • 互斥条件:指线程对已获取到的资源进行排它性使用,即该资源同时只由一个线程占用。
  • 请求并持有条件:指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源。
  • 不可剥夺条件:指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源。
  • 环路等待条件:指在发生死锁时,必然存在一个线程-资源的环形链。

如何避免线程死锁

资源的有序性破坏了资源的请求并持有和环路等待条件,因此避免了死锁。

十、守护线程与用户线程

Java线程分两类:守护线程和用户线程。
它们之间的区别在于,守护线程是否结束并不影响JVM的退出,但是只要有一个用户线程还没结束,正常情况下JVM就不会退出。
Tomcat的NIO实现NioEndpoint中的一组接收线程和处理线程属于守护线程。

十一、ThreadLocal

ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都有这个变量的一个本地副本。

ThreadLocal实现原理

在每个线程内部都有一个名为threadLocals的成员变量,该变量的类型是HashMap,其中key为我们定义的ThreadLocal变量的this的引用,value则为我们使用set方法设置的值。每个线程的本地变量存放在线程自己的内存变量threadLocals中,如果当前线程一直不消亡,那么这些本地变量会一直存在,所以可能造成内存溢出,因此使用完毕后要记得调用ThreadLocal的remove方法删除对应线程的threadLocals中的本地变量。

ThreadLocal不支持继承性

同一个ThreadLocal变量在父线程中被设置值后,在子线程是获取不到的。

InheritableThreadLocal类

特性就是让子线程可以访问父线程中设置的本地变量。
实现原理:InheritableThreadLocal类通过重写代码,让本地变量保存到了具体线程的inheritableThreadLcoals变量里面,那么线程在通过InheritableThreadLcoal类实例的set或者get方法设置变量时,就会创建当前线程的inheritableThreadLocals变量。当父线程创建子线程时,构造方法会把父线程中的inheritableThreadLocals变量里面的本地变量父子一份保存到子线程的inheritableThreadLcoals变量里面。

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值