1.1 java中的线程安全
线程安全是限定在多个线程之间存在共享数据访问前提下的,按照线程安全的安全程度,各种操作的共享数据可以分为:不可变、绝对线程安全、相对线程安全、线程兼容和线程对立。
线程安全的实现方法:同步和锁机制
(1)互斥同步:是常见的一种并发正确性保障手段。同步是指子啊多个线程访问共享数据时,保证数据在同一时刻只能被一个(或一些线程,在使用信号量的时候)线程使用。
而互斥是实现同步的一种手段,临界区(Critical Section),互斥量(Mutex),信号量(Semaphore)都是主要的互斥实现方式.。
Java中最基本的互斥同步手段就是synchronized关键字。注意:synchronized同步块对于同一条线程来说是可重入的;同步块在已进入的线程执行完前,会阻塞后面的线程。
除此之外还有ReentrantLock(重入锁)来实现同步。
(2) 非阻塞同步
互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步,它属于一种悲观的并发策略,即无论共享数据是否真的回发生竞争,它都要进行加锁。另一种处理策略是:乐观的并发策略:即先操作,如果没有其他线程争用共享数据,就操作成功;如果共享数据被争用,产生了冲突,就再采取补偿措施(常用的就是不断重复尝试)。这种策略不需要把线程挂起,因此这种同步操作称为非阻塞同步。
CAS指令需要有3个操作数,分别是:内存位置V、旧的预期值A、新值B。CAS指令执行时,仅当A和V的值相等时,才更新V 的值为B,否则不更新。
但是CAS存在一个逻辑漏洞:ABA问题。Atomic包中的类都是采用CAS实现的,,并通过控制变量值的版本来保证CAS操作的正确性。
(3)无同步方案
要保证线程安全,并不一定就要进行同步,两者没有因果关系。同步只是保证共享数据争用时的正确性的手段。如果一个方法本来就不涉及共享数据,自然就无需同步。
1.2 锁优化
自旋锁与自适应自旋
互斥同步对性能最大的影响是阻塞实现,挂起线程和恢复线程的操作都需要转达内核态中完成。有时共享数据的锁定状态持续时间很短,为此进行线程挂起和恢复不值得,所以可以让当前线程并不立即放弃CPU的执行权,而是执行一个忙循环(自旋),这项技术就是自旋锁。自适应的自旋锁意味着自旋时间不固定。
锁消除
锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。
锁粗化
锁粗化就是把加锁同步的范围扩大。
轻量级锁
该轻量级是相对于使用操作系统的互斥量来实现的传统锁而言。提升程序同步性能的依据是:对于绝大部分锁,在整个同步周期内都是不存在共享数据竞争的。
偏向锁
它的目的是消除数据在无竞争情况下的同步原语。