依据《Java 并 发编程实践》/《Java Concurrency in Practice》一书,一个线程安全的 class 应当满足三个条件:
- 从多个线程访问时,其表现出正确的行为
- 无论操作系统如何调度这些线程,无论这些线程的执行顺序 如何交织
- 调用端代码无需额外的同步或其他协调动作
不安全的多线程编程容易造成哪些后果
- 内存泄露
- 资源、数据访问冲突、数据不一致
- 进程空间用尽
- 计算资源耗尽
* 错误处理不当导致整个进程异常结束
数据访问
- 冲突
- 不一致
多线程间共享的标志变量, 可能被编译器优化,存储于cpu寄存器,一个线程将其值改变(内存值),在另一个线程的cpu寄存器对应的值却未同步。
解决方法: 1. 添加 volatile
关键字修饰变量。 并且加互斥锁。 2.不使用共享的标志变量。
内存空间使用的安全性
-
防止内存泄露,小心使用堆空间
-
小心使用栈空间
逻辑的安全性
-
参数检查一定要严格,任何一个不合法的参数能让线程异常,然后整个app异常
-
容错
内存泄露原因
软件的稳定性
- 如果一个线程体挂掉
?
- 悬空指针
释放时设置为NULL 声明定义时设置为NULL
线程空间限制
- 所有线程受限于进程的空间
- 系统会限制线程的栈空间(默认是10M)
在大规模软件设计中,线程数量的设定和栈空间的使用必须要小心。
高效使用栈空间技巧
- 如果使用大的内存空间,则到堆里去申请
- 不使用递归算法,而使用循环,也要避免使用递归算法的库
- 更加细致地拆分逻辑或模块,让函数体量更小
- 复杂数据类型(类或者结构体)做为函数参数时,尽可能传递它们的指针或引用,以节省栈空间
多线程下的设计模式
资源竞争与互斥
- 单例模式
循环中不使用wait
多线程下的全局变量、资源
线程安全
语言特性 valatile
内存泄露
和多进程编程相同的陷阱
运维的安全性
如果程序在线程在启动时固定,则在可动态扩展的容器中,可能会有因为线程数过多而不能充分使用cpu资源。在性能压力测试时,常常会引起在cpu资源使用率较低时,系统则已经到达瓶颈。