并发编程的核心和本质

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

本系列专栏 Java并发编程专栏 - 元浩875的专栏 - 掘金 (juejin.cn)

image.png

前言

并发编程不是一门相对独立的学科,而是一门综合学科,里面涉及的知识点很多,这篇文章先来说一说并发编程的核心和本质。

正文

不论学习什么知识点,最忌讳的就是"盲人摸象",这里有个非常好的学习方法叫做"跳出来,看全景"和"钻进去,看本质",并发编程虽然知识很多,但是都可以抽象为3个核心问题:分工、同步和互斥

分工

所谓分工,类似于现实中你是一个项目经理,你需要组织完成一个项目,需要把这些任务拆分,安排合适的人员去做;在并发编程中,员工就相当于是线程,你需要合理分配任务给到线程,因为这会直接决定了并发程序的性能。

Java中有很多分工的SDK,比如Executor、Fork/Join本质都是一个分工方法,还包括生产者-消费者设计模式,这些思想都是如何把一个任务给合理的分配出去

同步

分好工之后就是执行了,在项目执行中,任务之间是有依赖性的,比如需求评审完之后要让开发人员开始编码,那怎么通知这个后续任务去开始呢 在现实生活中就是靠沟通协作,这是一项非常重要的事。

在并发编程中,主要就是指的是线程之间的协作,和现实生活中没有区别,就是一个线程执行完了一个任务,如何通知后续任务的线程开工

协作一般和分工是相关的,比如Future可以发起一个异步调用,当主线程通过get()方法获取结果时,主线程就会等待,当异步执行结果返回时,get()方法就自动返回了,这个主线程和异步线程之间的协作,Future工具类帮我做好了。

在工作中线程协作问题,一般可以归纳为:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行。比如在生产者-消费者模型中,当队列满时,生产者线程等待,当队列不满时,生产者线程需要被唤醒执行;当队列为空时,消费者线程等待,当队列不为空时,消费者线程需要被唤醒执行。

互斥

分工、同步主要是强调性能,但在并发程序中还有一部分是关于正确性的,专业术语叫做"线程安全"。

在并发程序中,当多个线程同时访问一个共享变量时,结果是不确定的,而导致不确定的主要源头是可见性问题、有序性问题和原子性问题,为了解决这3个问题,Java语言引入了内存模型,内存模型提供了一系列的规则,利用这些规则,可以避免可见性、有序性问题,但是还不足以解决线程安全问题,解决线程安全的核心方案还是互斥。

互斥就是在同一时刻,只允许一个线程访问共享变量

实现互斥的核心技术就是锁,Java中的synchronized、SDK中的各种Lock都可以解决互斥问题,但是同时也带来性能问题,这就要分情况、分场景进行优化,比如ReadWriteLock、StampedLock可以优化读多写少的场景,还可以使用原子类这种无锁的数据结构。

总结

现在已经"跳出来,看全景"了,我们可以理解并发编程的核心和本质了,接下来的文章我们会不断地"钻进去,看本质",来解析和印证。

猜你喜欢

转载自juejin.im/post/7086621565793599495
今日推荐