D1
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"
分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的)
- 尝试获得锁
- 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)
注意点:
- 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock)
- 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。
对象锁的同步和异步问题
- 异步:t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
- 同步:t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
关于脏读
- 业务整体需要使用完整的synchronized,保持业务的原子性。
- setValue 和getValue,如果仅仅只是在setValue中添加synchronized的话,在获取getValue会出现问题
synchronized的重入
- 当前线程已经获得当前的对象锁,可以继续访问当前的对象
- 当前线程已经获得当前的对象锁,可以访问当前对象的父类的锁
对象锁
- 对象的改变,synchronized(字符串),str发生改变后,丢失锁
- synchronized代码块对字符串的锁,注意String常量池的缓存功能
- 尽量用不变的对象作为锁
- 同一个对象的属性改变,不会影响锁
- synchronized (this)也是对象锁
- private Object lock = new Object(); 任何对象锁
类锁
- synchronized (ObjectLock.class)
死锁
- 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况
优化
- 使用synchronized代码块减小锁的粒度,提高性能
数据库的ACID
A Atomicity 原子性
原子性是指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生。
转账,划钱和收账同时成功或者失败
C Consistency 一致性
一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNT表中aaa和bbb的存款总额为2000元。
做法
数据库中,设置约束
业务层面,校验
I Isolation 隔离性
多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
事务之间的相互影响分为几种,分别为:脏读,不可重复读,幻读,丢失更新
脏读
- 脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的;如下案例,此时如果事务1回滚,则B账户必将有损失。
不可重复读
- 不可重复读意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。如下案例,事务1必然会变得糊涂,不知道发生了什么。
幻读(虚读)
- 幻读,是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样
D 持久性
- 持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
oracle的undo表空间