哈喽,大家好,我是小米,一个喜欢分享技术的小伙伴!今天咱们来聊聊一个面试中常见但又容易被问懵的问题——如何在两个线程间共享数据。别急,先泡杯咖啡,听我用故事把这个问题讲清楚~
面试场景复盘:张三的“共享”迷惑
话说,有一天,咱们的主角张三去面试,面试官微微一笑:“张三啊,如果有两个线程需要共享一个变量,你会怎么实现?”
张三脑袋一热,先甩了个“用synchronized”,然后又补了句“volatile也行”。
面试官笑着点了点头:“嗯,那再深入一点,你觉得它们什么时候适合用?”
这下,张三慌了……
什么是线程间数据共享?
线程间共享数据,顾名思义,就是两个或多个线程可以同时访问或修改同一块数据。比如我们生活中的外卖订单系统:
- 用户下单 -> 系统创建订单(线程A)。
- 骑手接单 -> 系统更新订单状态为“配送中”(线程B)。
问题在于:如何保证线程A和线程B对同一订单的数据操作不会冲突?
用共享对象作为桥梁
故事情节:共享日记本
假如两个朋友小红和小明想通过写日记交流,每个人都可以往同一本日记本里写内容,但他们得约定:
- 一次只能有一个人动笔(线程同步)。
- 避免互相覆盖(数据一致性)。
用代码表示,我们可以用一个共享对象(比如Order类)来保存数据:
然后两个线程操作这个共享对象:
借助volatile实现轻量级共享
故事情节:实时天气广播
小红和小明在家看电视,电视播报当前的天气情况:
- 天气信息每秒更新一次(线程A)。
- 小红和小明随时可能抬头看看天气(线程B)。
在这种场景下,volatile可以用来保证共享变量的可见性:
线程操作:
注意: volatile只保证可见性,不保证操作的原子性,比如currentWeather++这种操作,仍需要synchronized或AtomicInteger来保护。
用Lock实现高级控制
故事情节:抢占篮球场
假如学校有一个篮球场,小红和小明需要使用它:
- 谁先抢到球,谁先用(公平性)。
- 用完后要交出来(释放资源)。
在Java中,Lock可以提供更灵活的控制:
两个线程操作:
面试官的“灵魂拷问”
1. volatile和synchronized区别是什么?
- volatile适用于简单的状态标记或变量更新;
- synchronized适合更复杂的线程同步逻辑,比如多个操作的原子性要求。
2. Lock相比synchronized有啥优势?
- 更灵活:可以尝试加锁或设置超时;
- 支持条件变量(Condition)实现更复杂的线程协调。
3. 数据共享的场景该如何选择?
- 简单标记更新:volatile。
- 单线程独占操作:synchronized或Lock。
- 更高并发需求:Lock或Atomic类。
总结与彩蛋
回到张三的面试题,你会怎么回答?以下是一个参考答案:
在两个线程间共享数据,常见的方式包括:
- 使用volatile保证变量的可见性;
- 使用synchronized或Lock保证原子性和互斥访问;
- 如果数据量较大,也可以使用线程安全的集合类,比如ConcurrentHashMap。
最后,别忘了告诉面试官:具体实现要看场景需求哦!
END
好了,今天的分享就到这里,希望大家喜欢!有什么问题可以留言讨论,小米随时在线~
点赞+在看,冲鸭!
我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!