一、sychronized实现线程同步
底层是将Java代码编译成字节码时添加一条monitorenter和两条monitorexit指令(保证任何情况下锁都能退出),修饰代码块时字节码显式的含有这两条语句,修饰方法时字节码中用一条ACC_SYNCHROZIED声明使用以上两条指令。
sychronized的锁对象(类/对象锁):
- 修饰静态方法则获取类锁,加锁的对象是该类的所有对象(因为所有对象共享静态方法);
- 修饰动态方法则获取对象锁,加锁的是该类的当前对象(每个对象有独立的动态方法)—由此可以实现Java的同步控制,多个线程同时执行该方法;
- 修饰方法块:使用A.class得到该类的类锁,使用this得到的是当前对象的对象锁;
ps:其余实现线程同步的方法还有Reentrantlock 配合countDownLatch,semaphore,condition,cyclicBarrier;ThreadLocal;AQS;volatile;原子类等(同步指的是多线程并发执行任务,同步控制就是要保证多线程对同一个数据操作时避免冲突)
二、多线程堆栈空间以及栈帧分布
一图胜千言:每个线程会有自己的栈空间,其中的每条栈帧对应线程执行的一个方法,每个栈帧会有执行方法时用到的局部变量表以及锁状态等字段信息(指向堆以及方法区中的对象,常量等),执行方法返回方法就对应入栈出栈。
ThreadLocal的内存溢出问题:所有的ThreadLocal对象都作为key被ThreadLocalMap弱引用,当GC时ThreadLocal会被回收,但是其对应的value是强引用不会被回收,所以用完ThreadLocal后(被回收后)要手动调用remove()方法回收key为null的value。
参考文章:
https://time.geekbang.org/column/article/13530