5. Java并发编程-Java线程状态、生命周期

首先Java中的线程对应到OS中的线程,深刻理解了OS中的线程学习Java中线程是非常简单的。

通用OS中线程状态

线程生命周期中涉及到五个状态,分别是:new(初始), ready(就绪), running(运行), block(阻塞)和terminated(终止)

new, ready, runnning, terminated比较好理解,重点分析一下block。

当运行态的线程调用了一个阻塞API(如读写文件),在条件变量上等待(wait),休眠(sleep), 等待其他线程结束(join)等,此时进入block状态。

Java中线程状态

Java中线程状态相比通用线程状态做了一些细分,包括:
1)NEW
2) RUNNABLE (就绪或运行中)
3)BlOCKED
4)WAITING
5) TIMED_WAITING
6) TERMINATED

Java中线程状态对阻塞状态做了细分, 用Runnable包括了就绪和运行中。

BLOCKED

只有当线程等待synchronized隐式锁时,线程会从RUNNABLE转换到BLOCKED状态。

WAITING

从RUNNABLE转换到WAITING有三种场景会触发这种转换。

1)获得synchronized隐式锁的线程,调用了无参数的wait()方法
2)调用了目标线程的join()方法,此时本线程会阻塞等待目标线程完成
3)调用了LockSupport.park()方法(jdk并发包中的锁是基于它实现)则线程重RUNNABLE变成WAITING, 当调用LockSupport.unpark(Thread t)又可唤醒目标线程,状态又从WAITING变成RUNNABLE。

TIMED_WAITING

有五种场景会触发这种状态转换:
1)调用Thread.sleep(long millis); 本线程会阻塞若干毫秒,期间不释放锁,时间到自行恢复
2)获得synchronized隐式锁的线程,调用了带参数的wait(long timeout)方法
3) 调用了目标线程带参数的join(long millis)方法,此时本线程会阻塞等待目标线程完成
4) 调用带超时参数的 LockSupport.parkNanos(Object blocker, long deadline) 方法;
5) 调用带超时参数的 LockSupport.parkUntil(long deadline) 方法。

TERMINATED

线程执行完run方法自动转换为TERMINATED状态,如果在run方法中抛出异常,线程也会终止。 另外如果需要强制终止线程执行,调用interrupt()方法。

interrupt vs stop
早期终止线程可以用stop方法,如今以及标记为@Deprecated, 原因是调用stop()方法后线程立即被kill,都没有释放锁的机会,导致其他线程获取不到锁。

interrupt如何使用
interrupt方法仅仅是通知线程,被interrupt的线程有机会执行一些后续操作,也可以无视这个通知。 可以通过捕获异常和主动检测的方式得到interrupt通知:
1)当线程处于WAITING,TIMED_WAITING时,线程会返回到RUNNABLE状态,且触发InterruptedException
2)当线程处于RUNNABLE时,并且阻塞在 java.nio.channels.InterruptibleChannel上时,会触发java.nio.channels.ClosedByInterruptException; 阻塞在java.nio.channels.Selector 上时,如果其他线程调用线程 A 的 interrupt() 方法,线程 A的 java.nio.channels.Selector 会立即返回
3)当线程处于RUNNABLE, 且并未阻塞在IO上,此时就得依赖线程主动检测了,通过 isInterrupted()方法判断。

jstack

jstack是一个jvm命令,当系统疑似出现活跃性问题(死锁,活锁,饥饿),我们需要使用该命令dump当前jvm线程栈,然后分析各线程的状态,排查问题。

jstack -l PID > dump.txt
如何设置正确的线程数

工作中常常会遇到诸如配置线程连接池,数据库连接池,tomcat连接数等,到底配置多少合适, 本节进行展开。

为什么需要使用多线程

目的当然是提升性能,充分利用多核CPU,使用吞吐量和延迟两个指标来度量,期望是低延时和高吞吐量。

多线程的应用场景

如何实现低延时和高吞吐量,基本有两个方向:优化算法和充分利用硬件性能。前者是算法方向,不是我们我们本文研究的重点,而第二硬件方面主要是两类:CPU和IO。并发编程中提升性能的本质就是提升CPU和IO的利用率。

创建多少线程合适

一般程序都是CPU计算和IO操作混合,两者交叉执行。如果IO操作执行的时间相比CPU执行时间要长很多,就可以称为IO密集型计算,反之称为CPU密集型应用。两个场景下,计算最佳线程数的方法是不同的

对于CPU密集型应用,多线程本质上是提升多核利用率,所以理论上运行线程数等于核心数就可以了,再多创建线程只会增加线程切换的成本,性能反而降低。在工程上一般设置为核心数+1

对于IO密集型应用,最佳线程数 =核心数 * (1 +(I/O 耗时 / CPU 耗时)), 如IO和CPU对半时,单个U最佳线程只需要2个即可。 在工程实践中可以设置为初始值:2*核心数 + 1, 通过压力测试的方式观察吞吐量和延迟,一般来讲IO/CPU会大于1,从压力测试的结果来看随着线程数的增加,吞吐量增加,延迟小幅增加,至吞吐量增长缓慢甚至开始下降,而延迟快速增加时即为最佳线程数。

用面向对象思想写好并发程序

可以从封装共享变量、识别共享变量间的约束条件和制定并发访问策略这三个方面下手。

封装共享变量

将共享变量作为对象属性封装在内部,对所有公共方法制定并发访问策略。对于不会发生变化的共享变量,使用final来修饰。

识别共享变量间的约束条件

识别这些约束条件很重要,因为这些约束条件,决定了并发访问策略。

制定并发访问策略

通常对应三种方案:
1)避免共享:如ThreadLocal
2) 不可变模式,即Immutable
3) 互斥锁:synchronized, 或并发包中的锁

总结

本节先学习了线程状态,再讨论了设置线程数的话题,最后总结了如何用面向对象思想写好并发程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Java并发编程是一项需要投入大量时间和精力的任务,但它在现代软件开发中是不可或缺的。通过深入学习线程、同步和异步、互斥和死锁线程安全性、并发编程模型以及Java并发包等内容,您可以成为一名更加优秀的编程专家。 对于初学者来说,Java并发编程可能会显得晦涩难懂,并且涉及了许多新技术。在学习这一领域之前,建议掌握好相关的理论知识,并打好基础。只有在掌握了基础知识后,才能更好地理解和应用更高层次的概念。 在进行Java并发编程的训练时,以下是一些建议: 1. 了解并掌握Java中的线程机制和线程生命周期。 2. 学习如何使用同步和异步机制来处理并发编程中的据共享和通信问题。 3. 理解并学习如何使用锁、互斥和死锁的概念以及如何避免它们。 4. 熟悉线程安全性的概念和相关的技术,如volatile关键字和Atomic类。 5. 学习并理解Java提供的并发编程模型,如线程池和Fork/Join框架。 6. 了解并掌握Java并发包中提供的各种类和工具,如Semaphore、CountDownLatch和CyclicBarrier等。 通过不断学习和练习,并发编程的技能会得到提升。建议您多实践编写并发程序,通过解决实际问题来加深对并发编程的理解。祝您在学习Java并发编程的过程中取得成功!<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* *2* [如何学习Java并发编程](https://blog.csdn.net/weixin_42080277/article/details/129785094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值