本文主要是介绍【并发编程实战】贯穿并发编程的核心三要素--分工/同步(协作)/互斥,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
并发编程相关的知识和技术还真是错综复杂,时至今日也还没有一张普遍认可的全景图,也许这正是很多人在并发编程方面难以突破的原因吧。
核心三要素
分工
现实生活中,为了提升工作效率肯定是要进行分工的,那么在程序里其实也是有分工的。分工的好坏决定了程序并发的性能,所以分工很重要又很复杂。
而Java SDK 并发包里的则提供了一系列的方法,例如 Executor、Fork/Join、Future 本质上都是一种分工方法。除此之外,并发编程领域还总结了一些设计模式,基本上都是和分工方法相关的,例如生产者 - 消费者、Thread-Per-Message、Worker Thread 模式等都是用来指导你如何分工的。
学习这部分内容,最佳的方式就是和现实世界做对比。例如生产者 - 消费者模式,可以类比一下餐馆里的大厨和服务员,大厨就是生产者,负责做菜,做完放到出菜口,而服务员就是消费者,把做好的菜给你端过来。不过,我们经常会发现,出菜口有时候一下子出了好几个菜,服务员是可以把这一批菜同时端给你的。其实这就是生产者 - 消费者模式的一个优点,生产者一个一个地生产数据,而消费者可以批处理,这样就提高了性能。
同步(协作)
当分工确定之后,需要确定的是 各个业务线之间的 信息同步和协作。
在并发编程领域里的同步,主要指的就是线程间的协作,本质上和现实生活中的协作没区别,不过是一个线程执行完了一个任务,如何通知执行后续任务的线程开工而已。协作一般是和分工相关的。
工作中遇到的线程协作问题,基本上都可以描述为这样的一个问题:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行。
管程:
在 Java 并发编程领域,解决协作问题的核心技术是管程,上面提到的所有线程协作技术底层都是利用管程解决的。管程是一种解决并发问题的通用模型,除了能解决线程协作问题,还能解决下面我们将要介绍的互斥问题。可以这么说,管程是解决并发问题的万能钥匙。
分工和同步的相关性:
Java SDK 并发包里的 Executor、Fork/Join、Future 本质上都是分工方法,但同时也能解决线程协作的问题。例如,用 Future 可以发起一个异步调用,当主线程通过 get() 方法取结果时,主线程就会等待,当异步执行的结果返回时,get() 方法就自动返回了。主线程和异步线程之间的协作,Future 工具类已经帮我们解决了。除此之外,Java SDK 里提供的 CountDownLatch、CyclicBarrier、Phaser、Exchanger 也都是用来解决线程协作问题的。
互斥
定义:所谓互斥,指的是同一时刻,只允许一个线程访问共享变量
核心:锁
锁:Java SDK 里提供的 ReadWriteLock、StampedLock 就可以优化读多写少场景下锁的性能。还可以使用无锁的数据结构,例如 Java SDK 里提供的原子类都是基于无锁技术实现的。除此之外,还有一些其他的方案,原理是不共享变量或者变量只允许读。这方面,Java 提供了 Thread Local 和 final 关键字,还有一种 Copy-on-write 的模式。
注意:死锁问题
总结:
学习并发编程需要从全景和本质两个方面着手。全景包括分工、同步和互斥三个核心问题,涉及任务拆分、线程分配、线程间协作和线程安全等方面。通过学习设计模式、Java SDK中的Executor、Fork/Join、Future等工具类,以及CountDownLatch、CyclicBarrier、Phaser等工具类,可以加深对并发编程的理解。同时,需要关注并发编程背后的理论模型,探索技术的本质,以建立知识体系,融会贯通。挖掘Java SDK并发包背后的设计理念,可以帮助快速建立解决并发问题的思路,梳理并发编程的知识,加深认识。探索技术背后的理论本质,不仅能加深对技术本身的理解,也能拓展知识深度和广度。因此,建议探求理论本质,共同进步
参考:
极客时间--Java并发编程实战
这篇关于【并发编程实战】贯穿并发编程的核心三要素--分工/同步(协作)/互斥的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!