前言:
继前一篇博客,今天咱们这篇博客来说说线程安全与线程同步那些事.
核心:
初识 synchronized关键字
可以实现一个简单的策略防止线程干扰和内存一致性错误,如果一个对象对多个线程是可见的那么对该对象的所有读或者写都将通过同步的方式来进行.
提供了一种锁的机制,能够确保共享变量的互斥访问,从而防止数据不一致问题的出现.
包含两个jvm命令,monitor enter和monitor exit两个JVM指令,它能够保证在任何时候任何线程执行到monitor enter成功之前都必须从主内存中获取数据,而不是从缓存中,在monitor exti运行成功之后,共享变量被更新后的值必须刷入主内存.
严格遵守java happens -before规则,一个monitor exti指令之前必定要有一个monitor enter.
synchronized关键字的用法:
可以对代码块或方法进行修饰,不能够用于对class以及变量进行修饰.
1.同步方法:
[default|public|private|protected] synchronized [static] type
2.同步代码块
Private final Object NUTEX = NEW Object();
Public
深入synchronized关键字
使用synchronized需要注意的问题
1.与monitor关联的对象不能为空
2.synchronized作用域太大
由于synchronized关键字存在排他性,也就是说所有的线程必须串行的经过synchronized保护的共享区域,如果synchronized作用域越大,则代表着其效率越低,设置还会丧失并发的优势
synchronized关键字应该尽可能的只作用于共享资源的读写作用域
3.不同的monitor企图锁相同的方法
4.多个锁的交叉导致死锁
this monitor和class monitor的详细介绍
程序死锁的原因以及如何诊断
程序死锁类似于交通堵塞现象
程序死锁:
交叉锁可导致程序出现死锁:线程A持有R1的锁等待R2的锁,线程B持有R2的锁等待获取R1的锁
内存不足:
当并发请求系统可用内存,如果此时系统内存不足,则可能会出现死锁的情况.
一问一答式的数据交换
服务端开启某个端口,等待客户端访问,客户端发送请求立即等待接收,由于某种原因服务端错误了客户端的请求,仍然在等待一问一答的数据交换
数据库锁
无论是数据库表级别的锁哈市行级别的锁,比如某个线程执行for update语句退出了事务,其他线程访问数据库时都将陷入死锁
文件锁
某线程获得了文件锁意外退出,其他读取文件的线程也将会进入死锁知道系统释放文件句柄资源
死循环引起的死锁
程序由于代码原因或者对某些异常处理不得当,进入了死循环,虽然查看线程堆栈信息不会发现任何死锁的迹象,但是程序不工作,CPU占有率又居高不下,这种死锁一般称为系统假死,是一种最为致命也是最难排查的死锁现象
HashMap不具备线程安全的能力,如果想要使用线程安全的map结构请使用concurentHashMap或者使用Collections.synchronizedMap来替代.
死锁诊断:
交叉锁引起的死锁,进入blocked状态,cpu资源占用不高,很容易借助工具来发现.打开jstack工具或者jconsole工具
死循环引起的死锁(假死):处于runnable状态,CPU使用率居高不下,甚至都不能够正常运行你的命令.
总结: