真的还有必要学习JAVA多线程吗?

简介: 真的还有必要学习JAVA多线程吗?

🔎这里是JAVA多线程加油站
👍如果对你有帮助,给博主一个免费的点赞以示鼓励
欢迎各位🔎点赞👍评论收藏⭐️

一、忘掉那该死的并行

Linus Torvalds是一个传奇式的人物(图1.1),是他给出了Linux的原型,并一直致力于推广和发展Linux系统。1991年,他首先在网络上发布了Linux源码,从此Linux 迅速崛起壮大,成为目前使用最广泛的操作系统之一。
在这里插入图片描述

  • 自2002年起,Linus就决定使用BitKeeper作为Linux内核开发的版本控制工具,以此来维护Linux的内核源码。BitKeeper
    是一套分布式版本控制软件,它是一套商用系统,由BitMover公司开发。2005年,BitKeeper宣称发现
    Linux内核开发人员使用逆向工程来试图解析BitKeeper 内部协议。因此,决定向Linus 收回
    BitKeeper授权。虽然Linux核心团队与BitMover公司进行了协商,但是仍无法解决他们之间的分歧。因此,Linus
    决定自行研发版本控制工具来代替BitKeeper。于是,Git诞生了。
  • 如果你正在使用Git,那么我相信你一定会为Git的魅力所征服;如果你还没有了解过Git,那么我强烈建议你关注一下这款优秀的产品。
  • 而正是这位传奇人物,给目前红红火火的并行计算泼了一大盆冷水。那么,并行计算究竟应该何去何从呢?

在 Linus的发言中这么说道:

Where the hell do you envision that those magical parallel algorithms would be used?
The only place where parallelism matters is in graphics or on the server side,where we alreadylargely have it. Pushing it anywhere else is just pointless.
So the whole argument that people should parallelise their code is fundamentally flawed. It restson incorrect assumptions.It's a fad that has been going on too long.

需要有多么奇葩的想象力才能想象出并行计算的用武之地?
并行计算只能在图像处理和服务端编程两个领域使用,并且它在这两个领域确实有着大量广泛的使用。但是在其他任何地方,并行计算毫无建树!
因此,人们争论是否应该将代码并行化是一个本质上的错误。这完全基于一个错误的假设。“并行”是一个早该结束的时髦用语。

  • 看了这段较为完整的表述,大家应该对Linus 的观点有所感触,我对此也表示赞同。与串行程序不同,并行程序的设计和实现异常复杂,不仅体现在程序的功能分离上,多线程间的协调性、乱序性都会成为程序正确执行的障碍。只要你稍不留神,就会失之毫厘,谬以千里!混乱的程序难以阅读、难以理解,更难以调试。所谓并行,也就是把简单问题复杂化的典型。因此,只有“疯子”才会叫嚣并行就是未来(Thecrazies talking about scaling tohundreds of cores are just that -crazy)。
  • 但是,Linus也提出了两个特例,那就是图像处理和服务端程序是可以也需要使用并行技术的。仔细想想,为什么图像处理和服务端程序是特例呢?
  • 和用户终端程序不同,图像处理往往拥有极大的计算量。一张1024×768像素的图片,包含多达78万6千多个像素。即使将所有的像素遍历一遍,也得花不少时间。更何况,图像处理涉及大量的矩阵计算。矩阵的规模和数量都会非常大。因为如此密集的计算,很有可能超过单核CPU的计算能力,所以自然需要引入多核计算了。
  • 而服务端程序与一般的用户终端程序相比,一方面,服务端程序需要承受很大的用户访问压力。根据淘宝的数据,它在“双11”一天,支付宝核心数据库集群处理了41亿个事务,执行285亿次SQL,生成15TB日志,访问1931亿次内存数据块,发生13亿个物理读。如此密集的访问,恐怕任何一台单核计算机都难以胜任,因此,并行程序也就自然成了唯一的出路。另一方面,服务端程序往往会比用户终端程序拥有更复杂的业务模型。面对复杂业务模型,并行程序会比串行程序更容易适应业务需求,更容易模拟我们的现实世界。毕竟,我们的世界本质上是并行的。比如,当你开开心心去上学的时候,妈妈可能在家里忙着家务,爸爸在外打工赚钱,一家人其乐融融。如果有一天,你需要使用你的计算机来模拟这个场景,你会怎么做呢?如果你就在一个线程里,既做了你自己,又做了妈妈,又做了爸爸,显然这不是一种好的解决方案。但如果你使用三个线程,分别模拟这三个人,一切看起来那么自然,而且容易被人理解。
  • 再举一个专业点的例子,比如基础平台Java虚拟机,虚拟机除了要执行main函数主线程外,还需要做JIT
    编译,需要做垃圾回收。无论是main
    函数、JIT编译还是垃圾回收,在虚拟机内部都是一个单独的线程。是什么使得虚拟机的研发人员这么做的呢?显然,这是因为建模的需要。因为这里的每一个任务都是相对独立的。我们不应该将没有关联的业务代码拼凑在一起,分离为不同的线程更容易理解和维护。因此,使用并行也不完全是出于性能的考虑,而有时候,我们会很自然地那么做。

二、可怕的现实:摩尔定律的失效

  • 摩尔定律是由英特尔创始人之一戈登·摩尔提出来的,其内容为:集成电路上可容纳的电晶体(晶体管)数目,约每隔24个月便会增加一倍。经常被引用的“18个月”,是由英特尔首席执行官大卫·豪斯所说:预计18个月会将芯片的性能提高一倍(即更多的晶体管使其更快)。
  • 说得直白点,就是每18个月到24个月,我们的计算机性能就能翻一番。
  • 反过来说,就是每过18个月到24个月,你在未来用一半的价钱就能买到和现在性能相同的计算设备了。这听起来是一件多么激动人心的事情呀!
  • 但是,摩尔定律并不是一种自然法则或者物理定律,它只是基于人为观测数据对未来的预测。按照这种速度,我们的计算能力将会按照指数速度增长,用不了多久,我们的计算能力就能超越“上帝”了!畅想未来,基于强劲的超级计算机,我们甚至可以模拟整个宇宙。
  • 摩尔定律的有效性已经超过半个世纪了,然而,在2004年,Intel宣布将4GHz芯片的发布时间推迟到2005年,在2004年秋季,Intel宣布彻底取消4GHz计划(如图1.2所示)。
  • 是什么迫使世界顶级的科技巨头放弃4GHz的研发呢?显然,就目前的硅电路而言,很有可能已经走到了头。我们的制造工艺已经精确到了纳米了。1纳米是10°米,也就是十亿分之一米。这已经是一个相当小的数字了。就目前的科技水平而言,如果无法在物质分子层面以下进行工作,那么也许4GHz的芯片就已经接近理论极限了。因为即使一个水分子,它的直径也有0.4纳米。再往下发展就显得有些困难。当然,如果我们使用完全不同的计算理论或者芯片生成工艺,也许会有本质的突破,但目前还没有看到这种技术被大规模使用的可能。

在这里插入图片描述
因此,摩尔定律在CPU的计算性能上可能已经失效。虽然,现在Intel已经研制出了4GHz芯片,但可以看到,在近10年的发展中,CPU主频的提升已经明显遇到了一些暂时不可逾越的瓶颈。

三、柳暗花明:不断地前进

  • 虽然CPU的性能已经几近止步,长达半个世纪的摩尔定律轰然倒地,但是这依然没有阻挡科学家和工程师们带领我们不断向前的脚步。
    从2005年开始,我们已经不再追求单核的计算速度,而着迷于研究如何将多个独立的计算单元整合到单独的CPU中,也就是我们所说的多核CPU。短短十几年的发展,家用型CPU,比如Intel
    i7就可以拥有4核心,甚至8核心。而专业服务器则通常可以配有几个独立的CPU,每一个CPU都拥有多达8个甚至更多的内核。从整体上看,专业服务器的内核总数甚至可以达到几百个。
  • 非常令人激动,摩尔定律在另外一个侧面又生效了。根据这个定律,我们可以预测,每过18个月到24个月,CPU的核心数就会翻一番。用不了多久,拥有几十甚至上百个CPU内核的芯片就能进入千家万户。
  • 顶级计算机科学家唐纳德·尔文·克努斯(Donald Ervin
    Knuth),如此评价这种情况:在我看来,这种现象(并发)或多或少是由于硬件设计者已经无计可施导致的,他们将摩尔定律失效的责任推给软件开发者。
  • 唐纳德(如图1.3所示)是计算机巨著《计算机程序设计艺术》的作者。《美国科学家》杂志曾将该书与爱因斯坦的《相对论》、狄拉克的《量子力学》和理查·费曼的《量子电动力学》等书并列为20世纪最重要的12本物理科学类专论书之一。

在这里插入图片描述

四、光明或是黑暗

  • 根据唐纳德的观点,摩尔定律本应该由硬件开发人员维持。但是,很不幸,硬件工程师似乎已经无计可施了。为了继续保持性能的高速发展,硬件工程师破天荒地想出了将多个CPU内核塞进一个CPU里的奇妙想法。由此,并行计算就被非常自然地推广开来,随之而来的问题也层出不穷,程序员的黑暗时期也随之到来。简化的硬件设计方案必然带来软件设计的复杂性。换句话说,软件工程师正在为硬件工程师无法完成的工作负责,因此,也就有了唐纳德的“他们将摩尔定律失效的责任推给了软件开发者”的说法。
  • 所以,如何让多个CPU有效并且正确地工作也就成了一门技术,甚至是很大的学问。比如,多线程间如何保证线程安全,如何正确理解线程间的无序性、可见性,如何尽可能地设计并行程序,如何将串行程序改造为并行程序。而对并行计算的研究,也就是希望给这片黑暗带来光明。

本文参考多线程高并发程序设计,非常棒的一本书,推荐xdm学习

相关文章
|
8天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
10天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
10天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
10天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
33 3
|
10天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
89 2
|
18天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
46 6
|
27天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
27天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
50 3
|
10天前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
33 1
|
3月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
62 1