synchronized可见性,synchronized保证三大特性
关于JAVA里的加锁synchronized
1.凡使用synchronized标记的方法,比如 public synchronized void func1() { .... },则同时只有一个线程能够运行这个方法。比如,线程1正在运行func1,则其他线程需要运行func1的话,会卡住,等线程1运行func1结束后,其他线程中,才会有一个幸运儿成功争取到运行func1的资格,然后这个幸运儿线程开始运行func1。没有争取到运行资格的其他线程,会继续等待。
2.你的例子中,被锁定的是 方法 m1,而不是属性b。所以,m1的synchronized加锁操作,与b没有半点毛钱关系。
3.要实现你的锁b想法,其实很简单。去买一件贞操宝甲来就行了。开玩笑,哈哈。要锁b,把main方法里的tt.m2()修改为tt.m1()。
4.以后别用“b”作为变量,总觉得怪怪了。也许你现在还没长大,很单纯。但大人的世界里,“b”是一种不文雅但又对人类的未来有重要作用的东西。建议用cb来代替b。
synchronized能保证可见性吗
volatile和synchronized的区别:
1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
3.volatile仅能实现变量的修改可见性,并能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
每日一问:谈谈 synchronized 和 CAS 机制
昨天的文章 我们针对 Java 语言的 "happends-before" 原则做了一个非常简单的表述,以致于有同学提到我这个话语的严谨性问题。而这个原则在 Java 语言里面非常重要,以致于我必须重新引用一下相关书籍的话来进行论述。
"happends-before" 先行发生原则是 Java 内存模型中定义的两项操作之间的偏序关系,如果说操作 A 先行发生于操作 B,那么操作 A 产生的影响一定应该被操作 B 所观察到。
而对于我们 volatile 保证的可见性, synchronized 和 final 关键字也同样可以做到。那我们今天就来简单讲一下我们非常常用的 synchronized 和似乎在 Android 中少有听到的 CAS 机制。
synchronized 采用的是 CPU 悲观锁机制,即线程获得的是独占锁。独占锁就意味着 其他线程只能依靠阻塞来等待线程释放锁 。而在 CPU 转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起 CPU 频繁的上下文切换导致效率很低。尽管 Java1.6 为 synchronized 做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低。
CAS 是英文单词 Compare And Swap 的缩写,翻译过来就是比较并替换。它当中使用了3个基本操作数:内存地址 V,旧的预期值 A,要修改的新值 B。采用的是一种乐观锁的机制,它不会阻塞任何线程,所以在效率上,它会比 synchronized 要高。所谓乐观锁就是: 每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
所以,在并发量非常高的情况下,我们尽量的用同步锁,而在其他情况下,我们可以灵活的采用 CAS 机制。
在 java.util.concurrent.atomic 包下,一系列以 Atomic 开头的包装类。例如 AtomicBoolean , AtomicInteger , AtomicLong 等,它们就是典型的利用 CAS 机制实现的原子操作类。
此外, Lock 系列类的底层实现以及 Java 1.6 在 synchronized 转换为重量级锁之前,也会采用到 CAS 机制。
关于 CAS 机制的更多相关信息请移步:
漫画:什么是CAS机制?(进阶篇)
synchronized和volatile区别
1、关键字不同
volatile?关键字是线程同步的轻量级实现,所以?volatile?性能肯定比synchronized关键字要好?。但是?volatile?关键字只能用于变量而?synchronized?关键字可以修饰方法以及代码块?。
2、修饰功能不同
volatile只能修饰变量,synchronized可以修饰方法、代码块。
3、线程阻塞情况不同
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
4、原子性不同
volatile保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存中和公共内存中的数据做同步。
谈谈synchronized与ReentrantLock的区别
【死记硬背】
synchronized是JVM层面的锁,是Java关键字,通过monitor对象来完成(monitorenter与monitorexit),对象只有在同步块或同步方法中才能调用wait/notify方法。
ReentrantLock是从jdk1.5以来(java.util.concurrent.locks.Lock)提供的API层面的锁。
1 都是用来协调多线程对共享对象、变量的访问;
2 都是可重入锁,同一线程可以多次获得同一个锁;
3 都保证了可见性和互斥性;
1 ReentrantLock显示的获得、释放锁,synchronized隐式获得释放锁;
2 ReentrantLock可响应中断、可轮回,synchronized是不可以响应中断的,为处理锁的不可用性提供了更高的灵活性;
3 ReentrantLock是API级别的,synchronized是JVM级别的;
4 ReentrantLock可以实现公平锁,而synchronized不行;
5 ReentrantLock通过Condition可以绑定多个条件;
6 底层实现不一样,synchronized是同步阻塞,使用的是悲观并发策略,Lock是同步非阻塞,采用的是乐观并发策略;
7 Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言
实现。
8 synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁。
9 Lock可以让等待锁的线程响应中断,而 synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
10 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到;
11 Lock 可以提高多个线程进行读操作的效率,既就是实现读写锁等;
【答案解析】
synchronized的锁使用案例:
ReentrantLock的锁使用案例:
【温馨提示】