Java中的synchronized关键字用于实现线程同步,即在多线程环境下保证共享资源的安全性。
当一个方法或代码块被synchronized修饰时,只有获得锁的线程才能执行该代码块或方法,其他线程则需要等待锁释放后才能执行该代码块或方法。
这个机制可以避免多个线程同时修改共享变量而引发的数据不一致问题,从而确保程序的正确性和稳定性。
synchronized 用法
一、作用于成员变量和非静态方法时,锁住的是同一个对象实例,即this对象。
synchronized method(){}
可以防止多个线程同时访问同一个对象的synchronized方法.
如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法。
当然, 不同对象实例的synchronized方法互不干扰。也就是说,在同一时间, 其它线程依然可以访问相同类的其他对象实例中的synchronized方法;
二、作用于静态方法时,锁住的是class,因为静态方法属于class而不属于对象。
synchronized static method{}
防止多个线程同时访问这个类中的synchronized static 方法。它对类的所有对象实例起作用。
三、作用于代码块时,锁住的是所有代码块中配置的对象。
如果是synchronized(T.class){}
,就和修饰静态方法一样都是锁住类了。
需要注意的是:
-
如果锁住的String变量是常量池中的对象(如
private final String lock = "baobao";
位于常量池中, 而使用new String("baobao")
会创建新对象),则所有线程都会加锁; -
如果锁住的Integer变量位于[-128, 127]区间中(其中127是
Math.min(Math.max(127, jvm启动时设置的变量-XX:AutoBoxCacheMax), Integer.MAX_VALUE-129)
,则所有线程都会加锁, 因为这区间的整数都存在于静态类IntegerCache的数组中; -
如果锁住的是Boolean变量的true或false,则所有线程都会加锁, 因为Boolean只有
true
和false
2个值;
synchronized 和 Lock 的区别
1)Lock 是一个接口;synchronized 是 Java 中的关键字,synchronized 是内置的语言实现;
2)Lock 在发生异常时,如果没有主动通过 unLock() 去释放锁,很可能会造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;synchronized 不需要手动获取锁和释放锁,在发生异常时,会自动释放锁,因此不会导致死锁现象发生;
3)Lock 的使用更加灵活,可以有响应中断、有超时等待等;而 synchronized 无法响应中断或超时等待,使用 synchronized 时,等待的线程会一直等待下去,直到获取到锁;
4)在性能上,随着近些年 synchronized 的不断优化,Lock 和 synchronized 在性能上已经没有很明显的差距了,所以性能不应该成为我们选择两者的主要原因。官方推荐尽量使用 synchronized,除非 synchronized 无法满足需求时,才考虑使用 Lock。
synchronized 和 volatile 的区别
- volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取, synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
- volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的;
- volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性;
- volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞;
- volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化.
网友评论