01.并发编程之synchronized
1、线程安全概念
当多个线程访问某一个类(对象或方法)时,这个类始终能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
synchronized
加锁的代码块称为“互斥区”或“临界区”。
锁竞争的问题,导致CPU使用率非常高,性能非常慢,宕机。
对象锁与类锁(静态方法上加synchronized
,类独占)。
2、对象锁的同步与异步
同步的需要线程去排队
同步的目的是为了线程安全,对于线程安全来说,需要满足:
(1)原子性(同步)
A线程先持有object
对象的Lock
锁,B线程如果在这个时候调用对象中的同步(synchronized
)方法,则需要等待,也就是同步。
A线程先持有object
对象的Lock
锁,B线程可以以异步的方式调用对象中的非同步方法。
(2)可见性
3、脏读
对于对象的同步和异步的方法,设计自己的程序时候,要考虑业务问题的整体,不然会出现数据不一致的错误。
ACID
:Oracle一致性读,9:00一刻的数据,发起select
查询,即使9:10分才查出来,9:05进行了更新,9:10分查询时,发现undo
有变化了,会去undo
中查询出来,绝对不会查询新值。如果客户端并发导致undo
丢失了,会抛snapshot too old
。
4、synchronized锁重入
当一个线程得到一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。(父子继承关系也可以)。
多线程处理多个任务中,要求同时成功或同时失败时,如中间出现异常时,可以printstackStrace
打印日志不进行中断,或者throw new RuntimeException
进行中断。
碰到异常,锁会立即释放,其他线程会进入,需要正确处理异常。如果对象由于线程未正确而释放了锁,可能会对后续的对象执行都是错误的处理逻辑。
PS:数据库中的存储过程,begin
与end
中才可以加exception when
5、不要使用"abc"这种作为锁对象
常量池中会造成死循环;可以使用new String("abc")
private String lock="lock"
作为锁对象后,不能进行更改该lock
,修改后,会引发锁释放。
但如果是对象作为锁对象,修改属性不影响锁的持有。