本文参考:https://nyimac.gitee.io/2020/06/08/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/#1%E3%80%81%E5%85%B1%E4%BA%AB%E5%B8%A6%E6%9D%A5%E7%9A%84%E9%97%AE%E9%A2%98
- 知道synchronized使用方法
- 知道变量是否逃逸,分析安全性(例如方法内的局部变量是安全的,因为与栈帧同时销毁)
- 只有读操作共享也安全
- synchronized底层原理是Monitor,Monitor用来识别锁对象(synchronized括号内的对象)是否已经被持有,它包含一个Owner属性,记录当前锁对象绑定的线程
- Monitor首先与锁对象绑定这样其它进程来访问时会查看Monitor。
- 线程查看Monitor如果已有主人就去EntryList里面去等待(阻塞)
- 各种级别的锁的特点:轻量锁,锁膨胀,自旋锁,偏向锁(所谓轻量锁就是没用monitor 而是用了thread record 放入锁对象object的头记录当中 )
- 知道CAS概念:compare and swap 属于乐观锁
- 了解wait&sleep¬ify等特点 等待队列waitset与entrylist
- 知道park的作用机制:notify只是随机的唤醒进程,使用unpark可以指定唤醒进程
- 在synchronized阻塞的线程(blocked)使用interrupt会打断阻塞进入runnable,而对于reentrantLock的interrupt是直接终止线程进入terminate
- 了解ThreadLocal与inheritableThreadLocal作用机制
synchronized使用
synchronized(对象) {
//临界区(不可由其他进程的打断的功能代码)
}
synchronized加在成员方法上
public class Demo {
//在方法上加上synchronized关键字
public synchronized void test() {
}
//等价于
public void test() {
synchronized(this) {
}
}
}
分析线程安全
Monitor机制
CAS机制
分级别上锁
wait¬ify&sleep
保护性暂停模式
park&unpark
使用park唤醒指定进程,park不会释放锁
状态转换
只有当线程创建并竞争时会进入blocked状态,其它调用方法会线程进入waiting或者是timed_waiting。
定位死锁
参考原文
ReentrantLock
还有可重入的特点
threadlocal
在每个线程内部都有一个名为threadLocals的成员变量,该变量的类型为HashMap,其中key为我们定义的ThreadLocal变量的this引用,value则为我们使用set方法设置的值。每个线程的本地变量存放在线程自己的内存变量threadLocals中
只有当前线程第一次调用ThreadLocal的set或者get方法时才会创建threadLocals(inheritableThreadLocals也是一样)。其实每个线程的本地变量不是存放在ThreadLocal实例里面,而是存放在调用线程的threadLocals变量里面
InheritableThreadLocal
它能够让父线程中ThreadLocal的值传给子线程。
也就是从main所在的线程,传给thread1或thread2
使用
public class Demo1 {
public static void main(String[] args) {
ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
InheritableThreadLocal<String> stringInheritable = new InheritableThreadLocal<>();
// 主线程赋对上面两个变量进行赋值
stringThreadLocal.set("this is threadLocal");
stringInheritable.set("this is inheritableThreadLocal");
// 创建线程
Thread thread1 = new Thread(()->{
// 获得ThreadLocal中存放的值
System.out.println(stringThreadLocal.get());
// 获得InheritableThreadLocal存放的值
System.out.println(stringInheritable.get());
});
thread1.start();
}
}
原理
InheritableThreadLocal类通过重写getMap和createMap,让本地变量保存到了具体线程的inheritableThreadLocals变量里面,那么线程在通过InheritableThreadLocal类实例的set或者get方法设置变量时,就会创建当前线程的inheritableThreadLocals变量。
当父线程创建子线程时,构造函数会把父线程中inheritableThreadLocals变量里面的本地变量复制一份保存到子线程的inheritableThreadLocals变量里面