1. 什么是线程安全
在多线程访问下, 不管哪个线程调用这个类,这个类总能表现出正确的行为
JMM 引发的问题
- 数据不一致, 缓存不一致
- 指令的重排序
怎样才能做到线程安全
1. 无状态类(没有成员变量的类)
public class A{
public void proc(int a, int b){
}
}
2. 让类不可变
public class A{
private final int x=0;// 安全的
private final user u = new user();//user 类里面与变量, 不能防止其他程序修改这个变量。是不安全的. 除非a也是final 的
public void proc(int a, int b){
}
class user{
int a;
}
}
- volatile
- 枷锁
- CAS
- 。。。。
线程不安全
- 死锁: 是指两个或者两个以上进程在执行过程中, 由于竞争资源, 或者由于彼此通信, 而造成的一种阻塞现象, 若无外力作用,他们都将无法推进下去, 此时称系统处于死锁状态或系统产生了死锁
简单的死锁:
代码示例:
A 线程拿到了1 资源, B线程拿到了2 资源, 但是A 也需要拿到2 资源才可以执行,B 需要拿到1 才能执行, 此时, 1被A 占着, 2 被B 占着, A 拿不到2 , B 拿不到1 。所以A和B 就死锁了
解决:两个线程同时拿1锁, 再拿2 锁
解决示例:
动态死锁
A 账户转给B 账户钱
先锁转出, 再锁转入
线程1 :张三转给李四
线程2:李四转给张三
则转入 和转出的账户, 是参数形式, 不固定
不安全操作
解决办法:使 在java system 类里面有个 identifyHashCode 对传入的参数进行排序, 先锁小的, 再锁大的, 出现hash碰撞后(算出的hashcoe 值一样), 可以进行加时处理使线程再重新跑一次
其他死锁:资源争夺 也会产生死锁
活锁:
显示锁Lock, 里面的tryLock() 尝试去拿锁, 拿不到时, 会释放这个说
线程A, 拿到锁1 后, 尝试拿锁2 , 线程B 哪到锁2 后尝试拿锁1, 1 和2 豆被线程占着, 所以线程A 会释放尝试拿2 的锁, 线程B 会释放拿1 的锁。 之后再尝试去拿, 线程在不断的尝试拿锁, 释放锁的过程。 此时线程A 和B 一直在运行, 但是此时运行时无效的
线程饥饿
:与线程优先级有关, 优先级高的线程总是会占有cpu, 优先级第的总是拿不到cpu 的使用权, 则优先级第的线程处于线程饥饿状态
提高性能
多线程代用calc 这个方法, 当a , b 数特别特别大的时候, 计算需要时间, 则, 调用这个方法的线程豆需要等待这个计算结果才能执行
优化后: