java多线程为什么有问题,为什么多线程是个坏主意

在 Unix编程艺术 中,提到了尽量避免多线程编程模型, 认为这样只会增加复杂度, 提倡使用多进程, 这样本质上就可以避免多线程『共享内存数据』产生的 “corruotped memory” 问题。

其中, 提到了一篇文章 Why Threads Are A Bad Idea, 对于多线程编程和事件编程分析的非常好, 具体的翻译如下:

1 介绍

线程的背景:

在操作系统中出现多线程

逐渐演变成 用户层面的编程工具

被认为是多种问题的一种通用解决方案

每一个程序员都需要成为 一个多线程编程的高手吗?

根本性的问题:

多线程的程序非常难以正确的编写!!!

替代性的方案:

使用事件驱动的编程方法

特别声明:

对于大部分的多线程程序,使用事件驱动是一个更好的选择

只有当使用CPU多核的时候, 才需要使用多线程编程

2 多线程的本质

razorerSnip20160809_109.png

一般用来管理并发问题

多个独立相互执行的任务

共享的内存

预先的安排机制(Pre-emptive scheduling)

同步机制(synchronization)

3 多线程的用途

操作系统: 对每一个用户进程分配一个内核线程

科学应用程序: 每个CPU分配一个线程(对计算要求性很高的程序)

分布式系统: 进程请求并行(同步记性的I/O操作)

GUIs程序

线程对应用户的行为. 在长时间的后台计算过程中仍然可以处理图形展示

多媒体, 动画方面的程序编写

4 多线程有什么问题?

razorerSnip20160809_110.png

对于一般的程序员而言,难以掌握。

即使对于专家,多线程编程也是痛苦的。

5 为什么多线程编程很难?

Synchronization(同步机制):

必须通过锁来共享数据

忘记了加锁?就会导致受污染的数据

死锁

依赖锁,会导致循环依赖

每个处理程序等待其他处理程序: 导致系统挂起

razorerSnip20160809_111.png

6 为什么多线程编程很难?

难以调试: 因为 数据依赖,时间依赖

线程破坏了抽象: 无法设计出模块化的程序

因为锁导致回调无法完成

razorerSnip20160809_112.png

7 为什么多线程编程很难?

很难达到非常好的性能

简单的锁导致了低并发

而精密的锁又会导致复杂度提升, 降低了一般情况下的性能

OSes限制了性能提升(调度, 环境切换)

线程不受支持

难以支持多线程代码(mac, windows)

一些标志库不是线程安全的

内核调用, windows系统不是多线程

很少有多线程编程的调试工具

通常不需要并发场景

8 时间驱动编程

一个执行流进程: 没有CPU的并发

在时间上注册消息(通过回调)

事件轮询等待消息, 调用处理器模型

时间处理器没有抢断

处理器通常是 短生命周期的

razorerSnip20160809_113.png

9 事件驱动编程被用来干什么

大多数的GUIs编程:

一个处理器对应一个事件

处理器用来执行行为(撤销,删除文件等)

分布式系统

一个处理器用来对应一个输入源

处理进来的请求,返回结果

事件驱动的I/O 来处理 I/O并发

10 事件驱动编程的问题

长时间运行的时间处理器会导致 程序没有反应, 解决办法:

对于长时间运行的程序Fork off子程序处理, 当处理结束后使用事件

打断处理器执行(比如: 事件驱动的I/O)

定期回调 时间处理器中的 事件循环

通过处理器无法维护本地内存状态(处理器必须返回)

没有CPU的并发(不太合适科学计算程序)

事件驱动的编程并不总是被支持

11 多线程编程 VS 事件驱动编程

事件驱动编发编程尽可能的避免 并发, 而多线程编程则倾向于并发:

使用事件驱动编程更加容易: 不用考虑并发, 不用考虑抢占, 不用考虑同步和死锁

只在特定的情况下,才使用复杂的技术栈

使用多线程编程, 即使最简单的程序也需要面对很高的复杂度(full complexity)

使用事件驱动更加容易调试

事件驱动编程只和时间依赖有关, 不需要考虑内部的调度

问题更加容易跟踪: 较慢的按钮点击反应 和 内存数据污染 时候, 前者问题更加容易定位

12 多线程编程 VS 事件驱动编程

在单个CPU上时间驱动程序比线程更加快速

没有锁的覆盖

没有上下文环境的 切换

事件驱动编程更加面向接口编程

多线程提供了真正的并发性

对于多CPU的机器来说,是可以扩展性能

可以长时间的运行处理程序而不需要冻结

13 你需要放弃多线程吗?

不需要的情况: 对于应该程序性能要求很高的服务(比如: 数据库服务器)

但是, 尽可能的避免多线程编程:

对于 GUIs程序, 分布式系统, 性能要求不高的, 使用事件编程, 不是多线程

只有当真正的多核CPU并发需要使用到的时候,使用多线程编程

当使用多线程编程的时候,将多线程编程模块与其他模块进行隔离, 保持大部分代码都是单线程模型

隔离多线程的模块:

razorerSnip20160809_114.png

14 总结

并发从根本上是很难的, 尽可能的避免

多线程比事件更加强大,但是这种强大的功能很少真正需要

多线程编程比事件编程更加难以写出正确的代码, 只有真正的专家才能掌握

将事件 编程当做基本的开发工具(对于GUIs 和 分布式系统)

只有当性能要求很高的服务时候,才使用 多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值