线程安全等级
不可变
不可变的对象一定是线程安全的,如final修饰的类和eunm枚举类。
final可以保证在构造过程中不会被其他线程访问到。
线程安全
ConcurrentHashMap等。
有条件的线程安全
复合操作的时候,用其他方法确保线程安全,比如加上synchronized。
线程兼容
正确使用同步,用锁或者synchronized块包含每一个方法调用。
线程对立
无论如何都不能确保线程安全。
同步和异步,阻塞和非阻塞
同步 阻塞式调用
调用方等响应方执行完毕才会返回。
阻塞:调用结果返回之前,当前线程会被挂起。
异步 非阻塞式调用
立即返回,调用方无需等待响应方返回实际结果,响应方会通过状态、通知和回调来告知调用方。
非阻塞:不会挂起,立即返回。
同步异步优劣势比较
\
同步
异步
优势
1.可以拿到实时结果进行处理,上下文信息始终在一个代码块,处理上方便直观 2.对错误和异常实时处理
1.不影响主流程执行,降低响应时间,提高应用的性能和效率 2.及时释放系统资源,如线程占用,让系统去做更多有价值的事
劣势
耗时的接口响应会影响流程的性能
1.为了保障数据的一致性,需要对系统做好监控和保障 2.需要更多的异步任务去补偿系统间的数据一致性
并发和并行
并发
单处理器,多线程,每一小段时间执行一小段的单线程,采用各种轮询方式。
并行
多处理器处理多线程,真正并行。
线程的状态
New
线程已经创建,但尚未调用start方法。
Runnable
可运行状态,已经在jvm虚拟机中执行,可能需要等待操作系统资源,比如处理器。有两种状态:正在被处理器执行running、等待处理器执行ready。
Blocked
正在等待监视器锁,进入同步代码块或方法。
Waiting
等待状态,调用了wait、join、park。需要其他线程中断或者通知来唤醒。
Timed_waiting
定时等待,在waiting基础上加了时间,在指定等待时间后返回,或者被提前中断或通知返回。
Terminated
终止线程,已完成。
线程方法
Thread.yield()
线程让步,当前线程退出时间片,但不代表自己不会竞争了,而是让出资源,大家一起抢。
Thread.sleep()
线程休眠,主动让出当前CPU时间,指定时间后,CPU返回继续执行该线程。
sleep方法不会释放当前的锁,比如synchronized。
Thread.join()
等待该线程死亡或终止。当前线程必须等到调用了join的线程执行完毕后才能继续执行。
Object.wait()
调用前必须拥有对象锁,比如在synchronized代码块中,调用wait方法后,对象锁会释放,线程进入waiting状态。
线程死锁和避免
多线程抢占多把锁,抢占顺序不一致。
避免:
不加锁,或者只有一把锁。
多把锁,确保对获取锁的顺序是一致的。
尝试获取具有超时释放的锁,比如lock的tryLock。
重启程序,干掉进程/线程。
定位死锁:
终端 jps 命令,拿到pid,再输入jstack pid(如jstack 1119) ,得到所有线程的状态。往下翻,有详细死锁说明。
jps:列举正在运行的虚拟机进程并显示虚拟机执行的种类以及这些进程的pid
jstack:JVM当前时刻的线程快照,得到JVM当前每一条线程正在执行的堆栈信息,定位线程长时间卡顿信息,如死锁、死循环
数据库死锁
对数据加锁顺序不一致。
数据库可以监测到死锁,第一个从等待状态转为正常状态。
commit提交第一个事务,解决死锁。