2019-11-03


前言:

  这个是我一个粉丝问我的问题,一个刚从python转Java的粉丝朋友。特此拿出来分享一下。希望能对大家在这块有迷惑的有所帮助。以下是他的问题

面试时多线程是Java绕不去的坎,就有几个问题

  1.为什么多线程在Java中这么重要?

  2.据说多线程会出现难以排查的BUG,那么使用协程的话能否避免这些BUG呢?

  3.go的协程是可以跑满整个核心的,但Java是不是除非从语言底层改造,否则做不到这一点?

  4.Kotlin支持协程,是否用起来比多线程好呢?

  5.所以,学好Java中的多线程是否还有必要呢?

答:

1.为什么多线程在Java中这么重要

  多线程在哪里都很重要

2.据说多线程会出现难以排查的BUG,那么使用协程的话能否避免这些BUG呢

  不能,其实协程需要学习的东西都更多。如果你学过C#的话,你去好好分析一个await函数里面的任意两行代码是不是执行在同一个线程里的,以及为什么,初学者都得头痛一阵子。然而你这个不知道的话,出了bug你连改都不会改。

  用了协程你也不可避免会遇到数据共享的问题,要共享你要么atom要么interlocked要么上锁,这完全是多线程的内容。这个时候你甚至得去弄明白协程跟线程在实现的时候是如何对应的,不然就抓瞎。

3.go的协程是可以跑满整个核心的,但Java是不是除非从语言底层改造,否则做不到这一点

  Java吧这个任务交给你了,你行程序就行,你不行程序就不行。

4.Kotlin支持协程,是否用起来比多线程好呢

  参见2

    所以,学好Java中的多线程是否还有必要呢

 学什么语言都有必要学多线程,除了不让你开线程的。(不是黑)

结论与思考

  先说结论:协程是非常值得学习的概念,它是多任务编程的未来。但是Java全力推进这个事情的动力并不大。

  先返回到问题的本源。当我们希望引入协程,我们想解决什么问题。我想不外乎下面几点:

  节省资源,轻量,具体就是:

  节省内存,每个线程需要分配一段栈内存,以及内核里的一些资源

  节省分配线程的开销(创建和销毁线程要各做一次syscall)

  节省大量线程切换带来的开销

  与NIO配合实现非阻塞的编程,提高系统的吞吐

  使用起来更加舒服顺畅(async+await,跑起来是异步的,但写起来感觉上是同步的)

我们分开来讲下。

1. 先说内存。拿Java Web编程举例子,一个tomcat上的woker线程池的最大线程数一般会配置为50~500之间(目前springboot的默认值给的200)。也就是说同一时刻可以接受的请求最多也就是这么多。如果超过了最大值,请求直接打失败拒绝处理。假如每个线程给128KB,500个线程放一起的内存占用量大概是60+MB。如果真的有瓶颈,也许CPU,IO,带宽,DB的CPU等会有瓶颈,但这点内存量的增幅对于动辄数个GB的Java运行时进程来说似乎并不是什么大问题。

2. 换一个场景,比如IM服务器,需要同时处理大量空闲的链接(可能要几十万,上百万)。这时候用connection per thread就很不划算了。但是可以直接改用netty去处理这类问题。你可以理解为NIO + woker thread大致就是一套“协程”,只不过没有实现在语法层面,写起来不优雅而已。问题是,你的场景真的处理了并发几十万,上百万的连接吗?

3. 再说创建/销毁线程的开销。这个问题在Java里通过线程池得到了很好的解决。你会发现即便你用vert.x或者kotlin的协程,归根到底也是要靠线程池工作的。goroutine相当于设置一个全局的“线程池”,GOMAXPROCS就是线程池的最大数量;而Java可以自由设置多个不同的线程池(比如处理请求一套,异步任务另外一套等)。kotlin利用这个机制来构建多个不同的协程scope。这看起来似乎会更灵活一点。

4. 然后是线程的切换开销。线程的切换实际上只会发生在那些“活跃”的线程上。对于类似于Web的场景,大量的线程实际上因为IO(发请求/读DB)而挂起,根本不会参与OS的线程切换。现实当中一个最大200线程的服务器可能同一时刻的“活跃线程”总数只有数十而已。其开销没有想象的那么大。为了避免过大的线程切换开销,真正要防范的是同时有大量“活跃线程”。这个事情我自己上学的时候干过,当时是写了一个网络模拟器。每一个节点,每一个链路都由一个线程实现。模拟跑起来后,同时的活跃线程上千。当时整个机器瞬间卡死,直到kill掉这个程序。

5. 此外说说与NIO的配合。在Java这个生态里Java NIO/Netty/Vert.X/rxJava/Akka可以任意选择。一般来讲,Netty可以解决绝大部分因为IO的等待造成资源浪费的问题。Vert.X/rxJava。可以让程序写的更加“优雅”一点(见仁见智)。Akka就是Java世界里对“原教旨OO“的实现,很有特色。的确,用NIO + completedFuture/handler/lambda不如async+await写起来舒服,但起码是可以干活的。

6. 如果真的要较真Java的NIO用于业务的问题,其核心痛点应该是JDBC。这是个诞生了几十年的,必须使用Blocking IO的DB交互协议。其上承载了Java庞大的生态和业务逻辑。Java要改自己的编程方式,必须得重新设计和实现JDBC,就像https://github.com/vert-x3/vertx-mysql-postgresql-client 那样做。问题是,社区里这种“异步JDBC”还没有支持oracle、sql server等传统DB。对mysql和postgres的支持还需要继续趟坑~

7. 如果认真阅读上面这些需要“协程”解决的问题,就会发现基本上都可以以各种方式解决。觉得线程耗资源,可以控制线程总数,可以减少线程stack的大小,可以用线程池配置max和min idle等等。想要go的channel,可以上disruptor。可以说,Java这个生态里尽管没有“协程”这个第一级别的概念,但是要解决问题的工具并不缺。

8. Java仅仅是没有解决”协程“在Java中的定义,以及“写得优雅“这个问题。从工程角度,“写得优雅”的优势并没有很多追新的人想象的那么关键。C#也并非因为有了async await就抢了Java的市场分毫。而反过来,如果java社区全力推进这个事情,Java历史上的生态的积累却因为协程的出现而进行大换血。想像一下如果没有thread,也没有ThreadLocal,@Transactional不起作用了,又没有等价的工具,是不是很郁闷?这么看来怎么着都不是个划算的事情。我想Oracle对此并不会有太大兴趣。OpenJDK的loom能不能成,如果真的release多少Java程序员愿意使用,师母已呆。据我所知在9012年的今天,还有大量的Java6程序员。

9. 其他新的语言历史包袱少,比较容易重新思考“什么是现代的multi-task编程的方式“这个大主题。kotlin的协程、go的goroutine、javascript的async await、python的asyncio、swift的GCD都给了各自的答案。如果真的想入坑Java这个体系的“协程”,就从kotlin开始吧,毕竟可以混合编程。

最后说一句,多线程容易出bug主要因为:

  “抢占“式的线程切换 —— 你无法确定两个线程访问数据的顺序,一切都很随机

  “同步“不可组装 —— 同步的代码组装起来也不同步,必须加个更大的同步块

  协程能不能避免容易出bug的缺陷,主要看能不能避免上面两个问题。如果协程底层用的还是线程池,两个协程还是通过共享内存通讯,那么多线程该出什么bug,多协程照样出。javascript里不出这种bug是因为其用户线程就一个,不会出现线程切换,也不用同步;go是建议用channel做goroutine的通讯。如果go routine不用channel,而是用共享变量,并且没有用Sync包控制一下,还是会出bug。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 姓名:刘伟勋 —宁波市镇海承迪文具有限公司 【日精进打卡第515天】 【知~学习】 《...
    君临天下_7055阅读 394评论 0 0
  • 也谈语文学习 沙区教研室 卿红燕 听过这样一个故事:很久以前,...
    41626a49b1c2阅读 148评论 0 1
  • 也谈语文学习 卿红燕 听过这样一个故事:很久以前,一位病危的老酋长...
    41626a49b1c2阅读 448评论 0 0
  • 生活中有很多的不经意。不经意间爱了,不经意间犯错了,不经意间收获了,不经意间被罚了...... 因着急...
    N落花成荫阅读 124评论 0 1
  • “姐姐,你若想他,便去见他吧。你便是要将熙国给他,我也不在意,反正这熙国的天下都是你打下来的。” 今晚的夜色很深,...
    狐则阅读 617评论 0 0