synchronized底层实现

 
分为对象锁 和类锁
 
举个例子 hashtable 线程安全 都加了synchronized 调用get方法时 其他的方法需要等待, 不然set更新了 你获取的值就不对了
 
 
 
 
对于类锁synchronized static,是通过该类直接调用加类锁的方法,而对象锁是创建对象调用加对象锁的方法,两者访问是不冲突的,对于同一类型锁锁住的方法,同一对象是无法同时访问的,因为调用类锁锁住的方法无法创建实例对象,所以同一个类中只有加了对象锁的两个方法可以被同时访问,前提是new两个对象。
 
 
 
 
JVM内存结构主要分为三大块:堆、栈和方法区。每个线程都有自己的一个虚拟机栈,栈保存着局部变量以及所有调用的方法的参数和返回值。其他线程无法访问该线程的栈中数据。栈仅能保存基本类型和对象引用,对象是存放在堆中的。堆内存和方法区中的静态变量等数据可以被线程共享,而同步处理针对的正是共享数据。
 
 
A. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 
B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。 
C. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
 
ps:操作的也就是 堆和方法区 也就是对象和常量
 
 
 
class SynchronizedDemo {
 
//锁方法 public synchronized void m() { System.out.printf("WUST"); }
 
//锁代码块 public void m2() { synchronized(this) { System.out.printf("WUST"); } } }
反编译如下
synchronized修饰的方法在字节码中添加了一个ACC_SYNCHRONIZED的flags,
同步代码块则是在同步代码块前插入monitorenter,
在同步代码块结束后插入monitorexit。
这两者的处理是分别是这样的
 
当线程执行到某个方法时,JVM会去检查该方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了那线程会去获取这个对象所对应的monitor对象(每一个对象都有且仅有一个与之对应的monitor对象),获取成功后才执行方法体,方法执行完再释放monitor对象,在这一期间,任何其他线程都无法获得这个monitor对象
 
。而线程执行同步代码块时遇到的monitorenter和monitorexit指令依赖monitor对象完成。这两者实现的方式本质上无区别,只是方法的同步是一种隐式的方式,不通过字节码实现。
同步和monitor有关,而monitor则和对象头有关。
 

posted @ 2021-03-09 16:08  随手格式化ya  阅读(75)  评论(0)    收藏  举报