第一个用法:
用法
为什么i的值不同?
以上3步并不是原子的(原子的不可分割)。
实践:
Synchronized地位:
synchronized的作用:
官方解释:
i++是线程不安全的:
i++ 这里分成了三部(所以不是原子性)
读取i的值
计算i+1
把i+1的计算结果写回内存中赋给i
缺陷111111111
缺陷111111111
同步11111111
synchronized性质:
可重入:指的是同一线程的外层函数获得锁之后,内层函数可以直接再次获取锁。
好处:避免死锁,提升封装性
不可中断:一旦这个锁已经被别人获得了,如果我还想获得,我只能选择等待或阻塞,直到别的线程释放这个锁。如果别人永远不释放锁,那么我只能永远地等下去。
1、两个线程同时访问一个对象的同步方法:一个一个执行。(加锁成功可以起到保护作用和同步效果)
2、两个线程访问的是两个对象的同步方法:同时执行。(没有起到保护作用和同步效果)
3、两个线程访问的是synchronized的静态方法:一个一个执行。
4、同时访问同步方法与非同步方法:同时执行。
5、访问同一个对象的不同的普通同步方法:一个一个执行。
6、同时访问静态synchronized和非静态synchronized方法:同时执行。
7、方法抛出异常后,会释放锁:会。
锁的特性
1. 可重入 好处:避免死锁 提高封装特性
2. 不可中断
缺陷
效率低
锁的释放场景少:正常执行完毕、异常抛出。
试图获取锁时不能设定超时,只能一直等。
不能中断一个正在试图获得锁的线程。
不够灵活
加锁放锁的时机的单一,相比之下读写锁更灵活。
无法知道结果
获取锁成功没?
对象锁
方法锁:this,即当前实例对象
同步代码块锁:自己制定锁
类锁
静态方法锁:类对象
只有一个Class对象:Java类可能会有很多个对象,但是只有1个Class对象。
Synchronized的作用:能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。
JVM会自动通过使用monitor来加锁和解锁,保证了同时只有一个线程可以执行指定代码,从而保证了线程安全,同时具有可重入和不可中断的性质。
1.使用读写锁 2.使用lock
1.效率问题 2.看业务,优先考虑synchronized(简单) 3.主要判断被锁的对象
直到等于0时,那个锁才算是彻底释放了
Synchronized编译后,会生成monitorenter-加锁,monitorexit释放锁
答案:1.先后 2.同时 3.先后 4.同时 5.先后 6.同时 7.会
本课程的知识点回顾
1、读写锁:读的时候可以多线程执行
2、将synchronized替换为lock