Java并发的四句箴言--中享思途
1.1 不要使用它
避免并发副作用的最简单方法就是不用。虽然它似乎足够安全,但它存在无数微妙的陷阱。
证明并发性的唯一因素是速度。只是希望运行更快是不合理的 - 首先应用一个分析器来发现你是否可以执行其他一些优化。
如果被迫并发,请采取最简单安全的实现。使用已有库并尽可能少写自己的代码。有了并发,就没有什么“简单事”。
1.2 一切都可能有问题
没有并发性的世界有一定的顺序和一致性。通过简单地将变量赋值给某个值,很明显它应该始终正常工作。
而在并发领域,必须质疑一切。即使将变量设置为某个值也可能不会按预期的方式工作。
在非并发程序中你可以忽略的各种事情突然变得非常重要。例如,你必须知道处理器缓存以及保持本地缓存与主内存一致的问题。必须了解对象构造的深度复杂性,以便你的构造对象不会意外地将数据暴露给其他线程更改。
1.3 起作用不意味着没问题
很容易编写出一个看似完美,实则有问题的并发程序,往往问题在极端情况下才暴露 - 在部署后不可避免地出现用户问题。
你无法证明并发程序是正确的,只能(有时)证明它是不正确的大多数情况下即使它有问题,你可能也无法检测到你通常无法编写有用的测试,因此必须依靠代码检查结合深入的并发知识来发现错误即使是有效的程序也只能在其设计参数下工作。当超出这些设计参数时,大多数并发程序会以某种方式失败。在其他Java主题中,我们培养了一种感觉-决定论。一切都按照语言的承诺(或隐含)进行,这是令人欣慰和期待的 - 毕竟,编程语言的目的是让机器做我们想要的。从确定性编程的世界进入并发编程领域,有种称为Dunning-Kruger效应的认知偏差概括为“你知道得越少,你以为你知道得越多。”这意味着,相对不熟练的人拥有着虚幻的自我优越感,错误地评估他们的能力远高于实际。
无论你多么确定代码是线程安全的,它可能已经无效了。你可以很容易地了解所有的问题,然后几个月或几年后你会发现一些概念让你意识到你编写的大多数内容实际上都容易受到并发错误的影响。当某些内容不正确时,编译器不会告诉你。为了使它正确,你必须在研究代码时在脑里模拟所有并发问题。
在Java的所有非并发领域,“没有明显的错误和没有明显的编译错误”似乎意味着一切都好。而对于并发,没有任何意义。
1.4 必须理解
在格言1-3之后,你可能会对并发性感到害怕,并且认为,“到目前为止,我已经避免了它,也许我可以继续避免。
你可能知道其他编程语言更好地设计用于构建并发程序 - 甚至是在JVM上运行的程序,例如Clojure或Scala。为什么不用这些语言编写并发部分并将Java用于其他所有部分呢?
唉,你不能轻易逃脱,即使你从未明确地创建一个线程,但可能你使用的框架创建了 - 例如,Swing或者像Timer定时器。最糟糕的事情:当你创建组件,你必须假设这些组件可能在多线程环境中重用。即使你的解决方案是放弃并声明你的组件“非线程安全”,你仍然必须知道这样的声明是重要的,它是什么意思
人们有时会认为并发性太难,不能包含在介绍语言的书中。认为并发是一个独立主题,在日常编程中出现的少数情况(例如图形用户界面)可以用特殊的习语来处理。如果你可以避免它,为什么要介绍这样的复杂的主题。不幸的是,你无法选择何时在Java程序中出现线程。你从未写过自己的线程,并不意味可以避免编写线程代码。例如Web系统本质上是多线程的Web服务器通常包含多个处理器,而并行性是利用这些处理器的理想方式。这样的系统看起来简单,必须理解并发才能正确地编写它。
Java是一种多线程语言,肯定存在并发问题。因此,有许多Java程序正在使用中,或者只是偶然工作,或者大部分时间工作并且不时地发生问题。有时这种问题是相对良性的,但有时它意味着丢失有价值的数据,如果你没有意识到并发问题,你最终可能会把问题放在其他地方而不是你的代码。如果将程序移动到多处理器系统,则可以暴露或放大这类问题。基本上,了解并发性使你意识到正确的程序可能会表现出错误的行为。
2 残酷的真相
Java是在充满自信,热情和睿智的氛围中创建的。在发明一种编程语言时,很容易就像语言的初始可塑性会持续存在一样,你可以把某些东西拿出来,如果不能解决问题,那么就修复它。一旦人们开始使用你的语言,变化就会变得更加严重。语言设计的过程本身就是一门艺术。通过匆忙设计语言而产生的认知负荷和技术债务最终会赶上我们。
Turing completeness是不足够的;语言需要更多的东西:它们必须能够创造性地表达,而不是用不必要的东西来衡量我们。解放我们的心理能力只是为了扭转并再次陷入困境,这是毫无意义的。我承认,尽管存在这些问题,我们已经完成了令人惊奇的事情,但我也知道如果没有这些问题我们能做得更多。
热情使原始Java设计师因为看起来有必要而投入功能。信心(以及原始语言)让他们认为任何问题都可以解决。有人认为任何加入Java的东西是固定的和永久性的 - 这是非常有信心,相信第一个决定永远是正确的,因此我们看到Java的体系中充斥着糟糕的决策。其中一些决定最终没有什么后果,例如你可以告诉人们不要使用Vector,但保留了对之前版本的支持。
线程包含在Java 1.0中。当然,并发性是影响语言的基本语言设计决策,很难想象以后才添加它,客观的说,当时并不清楚基本的并发性。像C能够将线程视为一个附加功能,因此Java设计师也纷纷效仿,包括一个Thread类和必要的JVM支持。C语言是原始的,这限制了它的野心。这些限制使附加线程库合理。当采用原始模型并将其粘贴到复杂语言中时,Java的大规模扩展迅速暴露了基本问题。在Thread类中的许多方法的弃用以及后续的高级库浪潮中,这种情况变得明显,这些库试图提供更好的并发抽象。
为了在高级语言中获得并发性,所有语言功能都会受到影响,例如标识符为可变值。在函数和方法中,所有不变和防止副作用的方法都会导致简化并发编程(纯函数式编程语言基础)的变化,但当时对于主流语言的创建者来说似乎是奇怪的想法。最初的Java设计师要么对这些选择有所了解,要么认为它们太不同了,并且会抛弃许多潜在的语言采用者。语言设计社区当时根本没有足够的经验来理解调整在线程库中的影响。
Java经历告诉我们,结果是相当灾难性的。程序员很容易陷入认为Java 线程并不那么困难的陷阱。工作的程序充满了微妙的并发bug。为了获得正确的并发性,语言功能必须从头开始设计并考虑并发性。Java将不再是为并发而设计的语言,而只是一种允许它的语言。尽管有这些基本的不可修复的缺陷,Java的后续版本添加了库,以便在使用并发时提升抽象级别。事实上,我根本不会想到有可能在Java 8中进行改进:并行流和CompletableFutures史诗般的变化。
该校与厚学网暂未合作,平台不保证课程的真实有效性。
如有侵权等争议,请及时与厚学网联系处理
网上报名
新闻资讯
更多>>-
青岛java培训机构哪家好?-思途教育
2016-07-15
-
青岛软件培训机构哪家好?-青岛软件培训
2017-05-24
-
青岛思途教育怎么样呢?
2016-07-28
-
从哪方面去选择青岛UI设计培训学校?
2017-05-24
-
学安卓开发要有什么基础?培训机构怎么选?
2017-05-24