Q:怎么感觉 Java 的 thread 的「术语」体系好混乱,完全记不住每个命名模块的 function?

    A:你不是一个人,因为 Java 在 concurrency 部分的命名、术语选择都极其傻 X。抛开具体的编程语言,从 OS(operating system)的角度去看,concurrency 所涉及的基本概念只有如下几个:

    1/ thread 本身,它是作为「最小执行器单位」的概念被提出来的。那么,从任务的角度看,每个 thread 就是一个「执行器」(executor)。

    2/ 只有「执行器」是没有意义的,还得要有需要被执行的「任务」。正如只有汽车引擎是没有意义的,还得有需要被完成的“旅途”。所以「任务」这个概念应该是自然而然被提出来的。

    但令人困惑的是,Java 并没有选择 Task 这个单词去命名需要被 thread 执行的任务,而是使用了 Runnable 这样一个晦涩的单词。

    不仅如此,对于「任务」具体执行「步骤/指令」的描述承载,它没有使用诸如 fillInstructions() 这样见名知意的方法名,而是使用了 run() 这个名称。

    为何 run 这个名字不好?因为作为 task 来讲,它本身应该是被 thread 执行的指令,它自己并不能主动执行。但用 run() 来命名,会给人一种错误的暗示:仿佛直接调用了这个方法就可以让任务立刻运行起来,即:仿佛 task 可以脱离 thread 的存在而被执行起来。这种错误的暗示,会让初学者极其困惑,其影响是毁灭性的。

    考虑 task 的正确 mindset 是应该将其当做写在草稿纸上的 instruction。而「草稿纸」本身不应有 run() 的行为,最多不过具备将 instruction 写/填充在纸上的功能。反过来,能够拥有「执行/run」这个 function 的对应应该只限于 executor,即:只有 thread 才具备 run() 的功能,而 task 则只有「呈现/描述指令」的功能。

    3/ 显然,面对一堆的 task,只有一个 thread 是不够的,这就涉及到对 thread 的批量管理,即:thread manager,这个概念即对应到 thread pool。如果仅仅是使用 thread pool 这个名称倒还好,但 Java 非常糟糕地选择了 ThreadPoolExecutor 这样的单词组合。

    thread 本身就是一个 executor,现在将 thread pool 又命名为 Executor,这会让人极其困惑,并且时不时地被这样的错误暗示所误导,搞错 thread 和 thread pool 的关系。仿佛是为了进一步加剧这种「术语命名」的离谱程度,为了在 Executor 的基础上进一步添加 thread pool 的 lifecycle 的控制,引入了一个继承自 Executor 的类 ExecutorService。WTF!!!

    仅从命名上看,foofooService 显然应该是一个后者包含前者实例的关系,但直接继承是个什么鬼?!当然,如果从它背后的意思:从 thread pool manager(Executor)过渡到 thread pool manager service(ExecutorService)还勉强可以理解。但基于错误的命名体系,进一步做更离谱的命名,实在是让人大跌眼镜。仿佛 Java 中如此重要的一个 Thread 模块,其命名方式就如同儿戏一般。

    我相信,即便是一个人已经具备 concurrency 背后关于 CPU/memory 的基础知识,一旦进入到 Java 这样的术语体系,也会瞬间懵逼。

    总体来讲,虽然 Java 对「多线程」的支持在 programming language 中已经算是出类拔萃的,但在底层模块核心术语的选择上,却是极其糟糕的。而不恰当的「命名」意味着对 developer 直觉的严重干扰。

    而如果你非常不幸地只会 Java,并没有接触过其它的编程语言、也没有掌握 OS 背后的基本原理,以 Java 作为学习「多线程」的开始,只会变成一场悲剧:从开始到放弃,从不懂到误解,从一片空白到混沌杂乱。

    Notes
    表面上,变量/函数名/类的命名是一件无关紧要的事情,甚至无非是稍微多想一步的事情。但事实是,「命名」的作用在 programming 的过程中被远远地低估了。因为在 coding 的过程中,你的思绪和思路会随时被「命名」所暗示、启发和指引。不恰当的、没有经过深思熟虑的命名,只会让 coding 变得越发困难和晦涩。

    如同上面提到的需要被重新的 run() 方法。可以想见,之所以这样命名是因为在 thread 中可以直接调用 Runnable 中的这个 run() 方法,然后顺理成章地就运行了起来。从这个视角来看,这样的命名是合适的。

    但显然,这个模块的开发者没有做更进一步的深思熟虑。他们没有清楚地意识到,能够执行 run() 这个行为的只有作为 executor 的 Thread 本身,而不是 task(对应到 Runnable)。这个主次关系、执行的「谓语」和被执行的「宾语」是开发团队没有深思熟虑、没有意识到的心理学错误暗示。

    我们需要做的,不仅是单纯地批判 Java 中 Thread 模块命名的糟糕性,更是要用它来作为警示,不断地提醒自己「命名」不是简单的取名,它事关重大,关系到你对后续开发者持续不断地心理学暗示、指引和启发。