Java并发并没有你想象的那么糟糕

发布于:2021-01-21 10:38:08

0

152

0

hadoop java java 8 教程

在这篇文章中,我们将介绍有关Java8流、Hadoop、ApacheSpark、Quasar光纤和反应式编程方法的一些您需要了解的知识,并帮助您保持循环,特别是在您不经常使用它们的情况下。这不是未来,而是现在。

我们在处理什么?

在谈到并发性时,描述当前问题的一个好方法是回答几个问题以更好地理解它:

  1. 这是一项数据处理任务吗?如果是的话,它能被分解成独立的作品吗?

  2. 操作系统、JVM和代码之间的关系是什么?(本机线程与轻量级线程)

  3. 涉及多少台机器和处理器?(单核与多核)

让我们逐一分析一下,找出每种方法的最佳用例。

1.从线程池到并行流

在单机上进行数据处理,让Java负责线程处理。

在Java8中,我们引入了新的流API,它允许对数据流应用聚合操作,如过滤、排序或映射。流允许的另一件事是在应用.parallelStream()时在多核机器上进行并行操作——使用Java7中引入的Fork/Join框架在线程之间分割工作。Java6的一个演变java.util.concurrency在库中,我们遇到了创建和处理工作线程池的ExecutorService。

Fork/Join也构建在ExecuterService之上,与传统线程池的主要区别在于它们如何在线程之间分配工作,从而支持多核机器。通过一个简单的ExecuterService,您可以完全控制工作线程之间的工作负载分配,确定线程要处理的每个任务的大小。另一方面,在Fork/Join中,有一个工作窃取算法,可以抽象线程之间的工作负载处理。简而言之,这允许将大型任务划分为较小的任务(分叉),并在不同的线程中进行处理,最终合并结果—平衡线程之间的工作。然而,这不是一个银弹。

有时平行流甚至会减慢你的速度,所以你需要好好想想。将.parallelStream()添加到方法中可能会导致瓶颈和速度减慢(在我们运行的这个基准测试中大约慢了15%),细线穿过线程的数量。假设我们已经运行了多个线程,并且在其中一些线程中使用了.parallelStream(),向池中添加了越来越多的线程。这很容易变成超出我们的核心所能处理的,并且由于增加了上下文切换而减慢了一切。

底线:并行流在一台机器上抽象处理线程,在核心之间分配工作负载。但是,如果您想有效地使用它们,请务必记住硬件不会产生超出您的机器所能处理的线程数。

2.apachehadoop和apachespark

重型起重:跨多台机器的大数据处理。

接下来是多台机器、数PB的数据和类似于从twitter或重型机器学习算法中提取所有提到Java的推文的任务。说到Hadoop,重要的是要采取另一个步骤并考虑更广泛的框架及其组件:Hadoop分布式文件系统(HDFS)、资源管理平台(YARN)、数据处理模块(MapReduce)以及Hadoop所需的其他库和实用程序(Common)。除此之外,还有其他可选工具,如运行在HDFS(HBase)之上的数据库、查询语言平台(Pig)和数据仓库基础设施(Hive)等。

这就是apachespark作为一个新的数据处理模块介入的地方,它以内存性能和使用快速执行的弹性分布式数据集(RDDs)而闻名,不像Hadoop MapReduce那样高效地使用内存(和磁盘)操作。Databricks发布的最新基准测试显示,Spark在对PB级数据进行排序时比Hadoop快3倍,而使用的节点则少10倍。

Hadoop的经典用例是查询数据,而Spark则以其快速运行的机器学习算法而闻名。但这只是冰山一角,正如Databricks所说:“Spark使Hadoop集群中的应用程序在内存中的运行速度提高了100倍,甚至在磁盘上运行时也提高了10倍”。

底线:Spark是Hadoop生态系统中的新星。有一种常见的误解,认为我们谈论的是一些不相关或相互竞争的东西,但我相信我们在这里看到的是框架的演变。

3.类星体纤维

将本机线程中断为虚拟轻量级线程。

我们已经有机会运行Hadoop,现在让我们回到单机。事实上,让我们进一步放大标准的多线程Java应用程序,并将重点放在单个线程上。就我们而言,HotSpot JVM线程与本机OS线程是一样的,只持有一个线程并在其中运行“虚拟”线程是fibres的全部内容。Java没有本机的光纤支持,但不用担心,平行宇宙的类星体让我们得到了覆盖。

Quasar是一个开源JVM库,它支持fibers(也称为轻量级线程),还充当Actor框架,稍后我将提到它。上下文切换是游戏的名字。由于我们受到内核数量的限制,一旦本机线程数量增加,我们就会承受越来越多的上下文切换开销。解决这一问题的一种方法是使用支持“多线程”的单线程进行光纤传输。看起来像是Threadception的病例。

光纤也可以看作是线程池的一种演变,它避免了我们在并行流中遇到的线程过载的危险。它们使扩展线程变得更容易,并允许大量并发的“轻”线程。它们不是用来替换线程的,应该用于相对频繁地阻塞的代码,就像它们充当真正的异步线程一样。

底线:Parallel Universe为Java中的并发提供了一种新的方法,虽然还没有达到v1.0,但绝对值得一试。

4.参与者和反应式编程

使用Java处理并发的其他模型。

在反应宣言中,新的运动被描述为4个原则:反应、弹性、弹性和信息驱动。这基本上意味着快速、容错、可扩展和支持无阻塞通信。

让我们看看阿克卡演员是如何支持这一点的。为了简化事情,可以把参与者想象成具有某种状态和某种行为的人,通过交换发往对方邮箱的消息来进行交流。作为一个整体,应该为每个应用程序创建一个Actor系统,其层次结构将任务分解为更小的任务,这样每个Actor最多只有一个监控Actor。参与者可以处理任务,将任务进一步分解并委托给另一个参与者,或者在失败的情况下,将任务升级到其主管。无论哪种方式,消息都不应该包含行为或共享可变状态,每个参与者都有自己的独立状态和行为。

这是从大多数开发人员习惯的并发模型的范例转变。我们在这里讨论的前三个主题中的进化有点偏离了。虽然它的起源可以追溯到70年代,但直到最近几年,它的复兴才开始受到关注,以更好地适应现代应用需求。平行宇宙的类星体也支持Actor,基于它的轻量级线程。实现上的主要区别在于光纤/轻量级线程。

底线:采用Actor模型可以减少对线程池的管理,而将其留给工具箱。兴趣的复兴来自于应用程序今天处理的问题,即具有更多内核的高度并发系统。

结论

我们已经介绍了四种使用并行或并行算法解决问题的方法,其中最有趣的方法是解决当今的挑战。希望这有助于激发您的兴趣,更好地了解今天并发的热门话题。

除了线程池之外,现在有一种趋势,就是将这一点负责任地委托给语言及其工具—将开发人员的资源集中在发布新功能上,而不是花费无数的时间来解决竞争条件和锁。

Java/Scala开发人员?Takipi检测代码中的所有异常和错误,并告诉您它们发生的原因。只需1分钟即可安装:请尝试Takipi。