超越线程池:Java并发并没有你想的那么糟糕

简介:

很多人一直唠叨着并发中的新概念。然而,许多开发人员还没有机会把过多的注意力都放在上面。在这篇文章中,我们将带您了解Java 8 streams、 Hadoop、 Apache Spark、 Quasar fibers以及响应式编程,让你迅速入门。尤其是如果你不经常用它们的话。一句话,它并不遥远,它就在我们身边。

超越线程池:Java并发并没有你想的那么糟糕

我们该怎么做?

谈到并发,一种很好的方式来形容当前的问题是来回答几个小问题以便更好的了解它:

它是一个数据处理任务么?如果是这样的话,它可以分解为独立的任务单元么?

操作系统、虚拟机和你的代码之间的关系是什么?(本地线程 VS 轻量级线程)

有多少机器和处理器参与?(单核 VS 多核)

让我们带着问题,一起找出每个问题的最佳答案吧。

1、从线程池到并行流

在Java 8中,我们了解到新的流API接口,它允许应用聚集操作,如筛选、排序或者映射数据流。流允许我们做的另一件事情是,在多核机器上应用并行操作。并行流 ——通过把Fork/Join框架引入Java 7将线程间的工作分离。Java 6并发库,我们看到了ExecutorService创建和处理我们的工作线程池,这不得不说是个进步。

Fork/Join也建立在ExecutorService之上,与传统的线程主要的区别在于如何在线程和支持多核的机器间分配工作。用一个简单的 ExecutorService你能完全控制工作线程之间的负载分布,确立每个任务的大小以便线程来处理。而Fork/Join,恰好有个work-stealing算法分配线程间的负载。简而言之,这允许大型任务可以被分成更小单元,并在不同的线程间处理,最终我们可以知道——它是为了平衡线程间的 工作。然而,这并不是万能的。

有时并行流会减慢你速度的,所以你需要多想想。在你的方法中使用parallelStream会导致瓶颈和减速(在我们基准测试中跑慢了约15%左右)。假设我们已经运行多个线程,在其中一些我们使用parallelStream,在线程池中添加越来越多的线程。这可以很容易超过我们的核心处理能力,由于增加了上下文转换一切都慢下来了。

小结:在单机上并行流使线程处理抽象化,在一定程度上这会均衡核心间的负载。然而,如果你想高效使用它们,记住硬件是关键而不是生产更多的线程而超出机器的处理能力。

2、Apache Hadoop和Apache Spark

接下来谈多核机器、 PB级数据和任务,这跟所有从twitter提到的Java或重载机器学习算法类似。谈到Hadoop,不得不说这个应用广泛的框架及它的组 件:Hadoop分布式文件系统(HDFS)、资源管理平台(YARN)、数据处理模块(MapReduce)和其他所需的类库和工具(Common)。 在这些组件上层还有一些其他很受欢迎的可选工具,比如运行在HDFS上的数据库(HBase)、查询语言平台(Pig)和数据仓库基础结构(Hive)。

Apache Spark 作为一种新数据处理模块,以内存性能和快速执行的弹性分布式数据集(RDDs)而出名,不同于不能高效使用内存和磁盘的Hadoop MapReduce。Databricks公布的最新标准显示当用少于10倍节点的时候,对1PB数据的排序Spark比Hadoop快三倍。

典型的Hadoop用例在于查询数据,而Spark正以其快速的机器学习算法越来越出名。但这只是冰山一角,Databricks如是说:“Spark 使应用程序在Hadoop集群中运行在内存中快100倍,当运行在磁盘中时甚至快10倍”。

小结:Spark是在Hadoop生态系统中的后起之秀,有一个常见的误解是我们现在经常谈它一些不合作或竞争的事情,但是我认为我们在这正在看到这个框架的发展。

3、Quasar fibers

我们有机会运行在Hadoop,现在让我们回到单机。事实上,在Java多线程应用程序和集中在单线程上,让我们眼光再长远些。就我们而言,HotSpot JVM线程与本地系统线程相同,持有一个线程并且运行在”虚拟“线程中,这在fibers中都包含的。Java没有原生的fibers支持,但是不要担 心,Quasar通过Parallel Universe解决了我们的问题。

Quasar 是一个开源的JVM库。它支持fibers(也称为轻量级线程),并且还充当框架的角色,在后面中我会提到。在这上下文转换是它本质的名字。当我们核心数 量有限,一旦本地线程数量越大我们就会收到越来越多的上下文开销。一种解决这个问题的方式是fibers,使用单线程支持”多线程“。这看起来像threadcepiton的一个实例。

Fibers还可以被视为一个从线程池的进化,当我们通过应用并行流的时候避开了线程过载的危险。他们更容易衡量线程和允许令人可观的并行”轻量“线程数量。它们不是为了取代线程,而是应该用在那些相对来说经常堵塞的代码中,就如同担任真正异步线程的角色。

小结:并行领域在Java并发性中正提供一种新的思路,虽然还没有版本发布,但是值得一试。

4、Actor和响应式编程

在响应式的官方言论中,最新的释义有4原则:响应、有弹性、灵活性和消息驱动。这基本意味着快速、容错、可伸缩的和支持非阻塞通信。

让我们看看Akka Actor是如果支持它的吧。简单来讲Actor有一个状态和一个特定的行为,通过交换消息沟通彼此的邮箱。一个Actor系统作为一个整体应该被每个应 用程序创建,拥有一个层次结构将任务分解成更小的任务以便每个角色最多只有一个监督的角色。一个角色也可以处理这个任务,通过委托给另一个角色将其进一步 分解或在实例失败的情况下,将它反馈给它的监督者。无论哪种方式,消息不应该包括行为或者共享可变的状态,每个角色都有一个独立的状态和行为。

它是一个从大多数开发者在使用的并发模型的思考模式的转移。尽管它起源于70年代,但是为了适应现代应用程序的要求,直到最近几年它才复苏。并行领域的Quasar也支持Actor,实现的主要区别在于fibers/轻量级线程。

小结:相反的,Actor模型需要管理线程池,让它远离使用工具包。今天面对这种应用程序处理的问题,尤其在我们可以处理拥有更多核心的高并发系统方面又重新有了关注。

总结

关于使用并发或者并行算法,我们今天通过介绍4种方法来解决问题来应对你需要的场景。希望这有 助于激起你的兴趣,以及在这大谈并发话题的现在开拓下你的视野。超越线程池,有一种将这委托给语言及它的工具的趋势——关注新的技术并应用它而不是花费无 数个小时解决竞态条件和锁。


来源:51CTO

相关文章
|
6天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
75 38
|
3天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
7天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
21 1
[Java]线程生命周期与线程通信
|
4天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
2天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
8 2
|
3天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
11 3
|
5天前
|
监控 安全 Java
Java多线程编程的艺术与实践
【10月更文挑战第22天】 在现代软件开发中,多线程编程是一项不可或缺的技能。本文将深入探讨Java多线程编程的核心概念、常见问题以及最佳实践,帮助开发者掌握这一强大的工具。我们将从基础概念入手,逐步深入到高级主题,包括线程的创建与管理、同步机制、线程池的使用等。通过实际案例分析,本文旨在提供一种系统化的学习方法,使读者能够在实际项目中灵活运用多线程技术。
|
3天前
|
缓存 安全 Java
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文将深入探讨Java中的多线程编程,包括其基本原理、实现方式以及常见问题。我们将从简单的线程创建开始,逐步深入了解线程的生命周期、同步机制、并发工具类等高级主题。通过实际案例和代码示例,帮助读者掌握多线程编程的核心概念和技术,提高程序的性能和可靠性。
8 2
|
4天前
|
Java
Java中的多线程编程:从基础到实践
本文深入探讨Java多线程编程,首先介绍多线程的基本概念和重要性,接着详细讲解如何在Java中创建和管理线程,最后通过实例演示多线程的实际应用。文章旨在帮助读者理解多线程的核心原理,掌握基本的多线程操作,并能够在实际项目中灵活运用多线程技术。
|
6天前
|
Prometheus 监控 Cloud Native
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
30 4