这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
2 什么是线程安全问题
线程安全 是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况
线程安全问题就是由多个线程 同时读写 同一个共享资源并且没有任何同步措施导致脏数据或者其他不可预见的结果的问题
2.1 三种典型安全问题
- 运行结果错误:线程拥有的时间片执行完成,但资源并没有同步,导致多个线程运行结果没有关联性的线程安全问题
- 发布或初始化:多线程导致的代码执行顺序不可控现象,初始化所在线程在调用线程之后执行,导致调用对象为 null
- 锁相关问题:
- 死锁:两个线程互相等待对方资源互不相让
- 活锁:线程并未发生阻塞,但一直获取不到结果所以始终需要执行
- 饥饿:某些资源始终获取不到,导致线程长时间得不到执行
2.2 多线程的性能开销
- 上下文切换
- 高速缓存失效「CPU 执行代码会预加载数据到高速缓存」
- 多线程协作开销「CPU 编译器重排序优化无法执行」
2.3 线程切换
多线程数是大于 CPU 个数的,为了保持多线程是同步执行的,所以采取 时间片轮转 的策略。
线程在时间片内占用 CPU 执行任务,时间片执行完,自身就会处于 就绪状态(Ready,Runnable 包含 Ready 和 Running 两种状态),等待 CPU 继续安排执行,在这个期间 CPU 可能被其他线程占用,带来的内存数据切换就是上下文切换。
2.5 线程死锁
两个以上的线程因资源争夺造成相互等待的现象被称为线程死锁。
- 互斥
- 不剥夺
- 请求和保持
- 循环等待
一般来说想要避免死锁只需要破坏掉线程死锁的一个必要条件即可。
保证资源的有序性就是最简单那有效的解决线程死锁的方法。
2.6 守护线程与用户线程
守护线程和用户线程的最大区别在于守护线程不会影响 JVM 的退出,而 JVM 退出时候必须等到所有用户线程结束,才会终止。
Thread.setDaemon(true) 可以设置线程为守护线程。