计算机系统应用教程网站

网站首页 > 技术文章 正文

synchronized锁 synchronized锁的是类还是对象

btikc 2024-10-12 10:48:02 技术文章 6 ℃ 0 评论

5.1Synchronized锁的特性互斥性:也就是在同一时间内,有且只有一个线程获取某个锁。可见性:在锁被释放之前,对共享资源的修改,对于随后获得锁的线程可以获取到最新的资源。5.2synchronized修饰静态方法和非静态方法的区别?Synchronized修饰静态方法时,称为类锁,修饰非静态方法时,称为对象锁。对象锁:锁住的是调用非静态方法的那个对象,比如,在B类中,创建对象A,调用对象A中的非静态方法,这个时候锁住的是对象A,如果再创建一个对象A2,也调用那个非静态方法,那么对象A和对象A2是可以同时调用那个方法,因为两个是不同的对象。类锁:就是synchronized修饰在静态方法上或者是synchronized(Class对象)。类锁和对象锁同时存在时,多线程访问时不会阻塞,因为他们不是一个锁。比如A类的静态方法有MethodA和MethodB,非静态方法MethodC,在B类中创建一个A类对象,启动两条不同的线程,第一种情况,分别调用MethodA和MethodB方法,这个时候会有线程堵塞,因为静态方法加锁属于类锁,即这个类只有一个Class对象。第二种情况,分别调用MethodA和MethodC,这个时候不会有线程堵塞,因为调用的MethodA是Class对象锁,而调用MethodC是属于对象锁。

5.3synchronize在1.6之后的优化?增加了偏向锁、轻量锁(自旋的方式)。因为在申请获取锁的过程,jvm需要向操作系统申请一个mutex(互斥量),从用户态转变为核心态。释放锁的过程,需要从核心态转变为用户态。这个转变的过程,很耗性能。于是就添加了偏向锁和轻量锁。5.3.1自旋锁是指当一个线程尝试获取某个锁时,如果该锁被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或者是睡眠状态。该锁时为了解决频繁阻塞和唤醒线程,减轻CPU负担。该锁也只能适应于锁占用的时间短,否则反而加大CPU的负担。Jdk1.6是默认开启的5.3.2自适应自旋锁自旋的次数不是固定的,是根据上次自旋时间以及获取锁的情况而定。线程如果自旋成功了,那么下次自旋的次数就会增多,因为虚拟机认为上次成功获得锁,这次也可能会再次获得。如果线程自旋失败,那么下次自旋的次数就会减少,因为虚拟机认为上次获得锁失败,那么这次也可能会失败。5.3.3消除锁消除锁可以节省毫无意义的请求锁的时间,也就是jvm检测到不可能存在有共享数据的竞争时,jvm就会对这些同步锁进行消除。比如jdk内置的API,StringBuffer、Vector5.3.4锁粗化就是将多个连续的加锁、解锁操作连接在一起,扩展成一个更大范围的锁。因为一系列的加锁和解锁,会造成性能消耗过大,故而引入了锁粗化的概念。5.3.5偏向锁偏向锁是在单线程执行代码的机制,如果是多个线程并发的环境下(即A线程尚未执行完代码块,B线程发起了申请锁的申请),这个情况会转化为轻量锁或者重量锁。在没有多线程竞争的情况下,jvm只需要在对象头的Markword记录该线程的线程id,并且修改锁标识位为01。当该线程再次进入到临界区(也就是synchronize要同步的代码)时,只需要检查一下Markword中的线程id即可。5.3.6轻量级锁当关闭偏向锁或者多个线程同时竞争偏向锁时会导致偏向锁升级为轻量级锁。当线程检查Markword的线程id不是该线程时,使用CAS将线程id替换成Markword,如果成功,那还是偏向锁。如果失败,说明存在竞争,需要在栈帧中分配一个空间,名叫锁记录。当前线程将对象头的Markword替换为锁记录,如果成功,将获得锁,如果失败,表示其他线程竞争锁,便尝试使用自旋来获取,如果自旋能获取,说明是轻量锁,如果自旋失败,则为重量级锁。5.4synchronized的可重入性?一个线程在调用synchronize方法的同时也在其内部调用该对象的另一个synchronize方法,也就是说一个线程获取到一个对象锁的时候,再次请求该对象锁,这个是允许的,这个就是synchronize的可重入性。作用是可以避免出现死锁现象,比如子类同步方法调用了父类同步方法。5.5synchronize与lock的区别1.lock是一个接口,而synchronize是java的一个关键字2.Lock需要手动释放锁,而synchronize可以自动释放锁3.Lock可以在线程执行过程中中断任务,而synchronize不能,只能等待线程执行完毕4.Lock可以知道当前线程是否获取到锁,而synchronize不能。5.Lock是锁住块范围,而synchronize能锁住类、方法、代码块。5.6synchronize同步代码块的原理是什么?首先是synchronize获得锁后才能执行同步的代码,退出或者抛异常时必须要释放锁,这两点的实现就是synchronize的原理。主要依赖于monitor(监视器锁)。每个对象都有一个监视器锁,当监视器锁被占用时就会处于被锁状态,线程执行monitorenter指令获取监视器锁的所有权过程:获取锁:1.如果监视器锁的进入数为0,则该线程进入监视器锁,然后将进入数设置为1,那么该线程就获取了监视器锁的所有权。2.当线程已经占有该监视器锁的时候,只是重新进入,把进入数加1即可。3.如果其他线程已经占有该监视器锁,那么该线程就处于阻塞状态,直到监视器锁进入数为0时,才可以再重新尝试获取监视器锁的所有权。释放锁:执行Monitorexit指令时,监视器锁的进入数减1,如果减1后,监视器锁的进入数为0的话,那么表示该线程退出监视器锁,不再是监视器锁的所有者。5.7synchronize方法同步原理是什么?方法的同步并不是通过monitor和monitorenter指令来实现的,而是通过常量池中的ACC_SYNCHRONIZED标识符实现的。当方法被调用时,调用指令会检查ACC_SYNCHRONIZED是否被设置,如果被设置了,该线程将先获得monitor,获取成功之后才能执行同步方法的代码,方法执行完后再释放monitor。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表