网易Java研发面试官眼中的Java并发——安全性、活跃性、性能

本文深入探讨了并发编程中常见的三大挑战:安全性问题(数据竞争、竟态条件)、活跃性问题(死锁、活锁、饥饿)及性能问题。通过具体实例分析,介绍了线程安全的重要性及其解决方案,如锁、无锁算法等。

一. 安全性问题

  1. 线程安全的本质是正确性,而正确性的含义是程序按照预期执行

  2. 理论上线程安全的程序,应该要避免出现可见性问题(CPU缓存)、原子性问题(线程切换)和有序性问题(编译优化)

  3. 需要分析是否存在线程安全问题的场景:存在共享数据且数据会发生变化,即有多个线程会同时读写同一个数据

  4. 针对该理论的解决方案:不共享数据,采用线程本地存储(Thread Local Storage,TLS);不变模式

Ⅰ. 数据竞争

数据竞争(Data Race):多个线程同时访问同一数据,并且至少有一个线程会写这个数据

1. add

private static final int MAX_COUNT = 1_000_000;
private long count = 0;
// 非线程安全
public void add() {
	int index = 0;
	while (++index < MAX_COUNT) {
		count += 1;
	}
}

2. add + synchronized

private static final int MAX_COUNT = 1_000_000;
private long count = 0;
public synchronized long getCount() {
	return count;
}
public synchronized void setCount(long count) {
	this.count = count;
}
// 非线程安全
public void add() {
	int index = 0;
	while (++index < MAX_COUNT) {
		setCount(getCount() + 1);
	}
}
  • 假设count=0,当两个线程同时执行getCount(),都会返回0
  • 两个线程执行getCount()+1,结果都是1,最终写入内存是1,不符合预期,这种情况为竟态条件

Ⅱ. 竟态条件

  1. 竟态条件(Race Condition):程序的执行结果依赖于线程执行的顺序
  2. 在并发环境里,线程的执行顺序是不确定的
    • 如果程序存在竟态条件问题,那么意味着程序的执行结果是不确定的

1. 转账

public class Account {
	private int balance;
	// 非线程安全,存在竟态条件,可能会超额转出
	public void transfer(Account target, int amt) {
		if (balance > amt) {
			balance -= amt;
			target.balance += amt;
		}
	}
}

Ⅲ. 解决方案

面对数据竞争和竟态条件问题,可以通过互斥的方案来实现线程安全,互斥的方案可以统一归为锁

二. 活跃性问题

活跃性问题:某个操作无法执行下去,包括三种情况:死锁、活锁、饥饿

Ⅰ. 死锁

  1. 发生死锁后线程会相互等待,表现为线程永久阻塞
  2. 解决死锁问题的方法是规避死锁(破坏发生死锁的条件之一)
    • 互斥:不可破坏,锁定目的就是为了互斥
    • 占有且等待:一次性申请所有需要的资源
    • 不可抢占:当线程持有资源A,并尝试持有资源B时失败,线程主动释放资源A
    • 循环等待:将资源编号排序,线程申请资源时按递增(或递减)的顺序申请

Ⅱ. 活锁

  • 活锁:线程并没有发生阻塞,但由于相互谦让,而导致执行不下去
  • 解决方案:在谦让时,尝试等待一个随机时间(分布式一致算法Raft也有采用)

Ⅲ. 饥饿

  1. 饥饿:线程因无法访问所需资源而无法执行下去
    • 线程的优先级是不相同的,在CPU繁忙的情况下,优先级低的线程得到执行的机会很少,可能发生线程饥饿
    • 持有锁的线程,如果执行的时间过长(持有的资源不释放),也有可能导致饥饿问题
  2. 解决方案
    • 保证资源充足
    • 公平地分配资源(公平锁) – 比较可行
    • 避免持有锁的线程长时间执行

三. 性能问题

  1. 锁的过度使用可能会导致串行化的范围过大,这会影响多线程优势的发挥(并发程序的目的就是为了提升性能
  2. 尽量减少串行,假设串行百分比为5%,那么多核多线程相对于单核单线程的提升公式(Amdahl定律)
    S=1/((1-p)+p/n),n为CPU核数,p为并行百分比,(1-p)为串行百分比
  • 假如p=95%,n无穷大,加速比S的极限为20,即无论采用什么技术,最高只能提高20倍的性能

Ⅰ. 解决方案

  1. 无锁算法和数据结构
    • 线程本地存储(Thread Local Storage,TLS)
    • 写入时复制(Copy-on-write)
    • 乐观锁
    • JUC中的原子类
    • Disruptor(无锁的内存队列)
  2. 减少锁持有的时间,互斥锁的本质是将并行的程序串行化,要增加并行度,一定要减少持有锁的时间
    • 使用细粒度锁,例如JUC中的ConcurrentHashMap(分段锁)
    • 使用读写锁,即读是无锁的,只有写才会互斥的

Ⅱ. 性能指标

  1. 吞吐量:在单位时间内能处理的请求数量,吞吐量越高,说明性能越好
  2. 延迟:从发出请求到收到响应的时间,延迟越小,说明性能越好
  3. 并发量:能同时处理的请求数量,一般来说随着并发量的增加,延迟也会增加,所以延迟一般是基于并发量来说的

Java_supermanNO1:专注于Java开发技术的研究与知识分享!

————END————

  • 点赞(编辑不易,感谢您的支持)

  • 转发(分享知识,传播快乐)

  • 关注(每天更新Java开发技术)

潮汐研究作为海洋科学的关键分支,融合了物理海洋学、地理信息系统及水利工程等多领域知识。TMD2.05.zip是一套基于MATLAB环境开发的潮汐专用分析工具集,为科研人员与工程实践者提供系统化的潮汐建模与计算支持。该工具箱通过模块化设计实现了两大核心功能: 在交互界面设计方面,工具箱构建了图形化操作环境,有效降低了非专业用户的操作门槛。通过预设参数输入模块(涵盖地理坐标、时间序列、测站数据等),用户可自主配置模型运行条件。界面集成数据加载、参数调整、可视化呈现及流程控制等标准化组件,将复杂的数值运算过程转化为可交互的操作流程。 在潮汐预测模块中,工具箱整合了谐波分解法与潮流要素解析法等数学模型。这些算法能够解构潮汐观测数据,识别关键影响要素(包括K1、O1、M2等核心分潮),并生成不同时间尺度的潮汐预报。基于这些模型,研究者可精准推算特定海域的潮位变化周期与振幅特征,为海洋工程建设、港湾规划设计及海洋生态研究提供定量依据。 该工具集在实践中的应用方向包括: - **潮汐动力解析**:通过多站点观测数据比对,揭示区域主导潮汐成分的时空分布规律 - **数值模型构建**:基于历史观测序列建立潮汐动力学模型,实现潮汐现象的数字化重构与预测 - **工程影响量化**:在海岸开发项目中评估人工构筑物对自然潮汐节律的扰动效应 - **极端事件模拟**:建立风暴潮与天文潮耦合模型,提升海洋灾害预警的时空精度 工具箱以"TMD"为主程序包,内含完整的函数库与示例脚本。用户部署后可通过MATLAB平台调用相关模块,参照技术文档完成全流程操作。这套工具集将专业计算能力与人性化操作界面有机结合,形成了从数据输入到成果输出的完整研究链条,显著提升了潮汐研究的工程适用性与科研效率。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值