ReenTrantLock :锁
lock(); unlock()
Condition:同步监视器
Condition的作用是对锁进行更精确的控制
await() ;singal() ;singalAll();
对象监视器:
wait();notify();notifyAll();
锁:
1.公平锁与非公平锁:
公平锁:指按照线程加锁的顺序来分配,即FIFO先到先得
非公平锁:采取一种锁的抢占式机制,随机获得锁。
(效率更高,但有可能会造成某些线程一直获取不到锁,死锁)
2.共享锁与排它锁(读写锁)
共享锁:一个线程持有读锁的情况下,该线程可以对锁中的内容进行读写操作,其它线程也可以获得该读锁,但只能进行读的操作。
排它锁:一个线程持有写锁的情况下,该线程可以对锁中的内容进行读写操作,其它线程无法获取到该锁。
写锁可以获得读锁,但读锁不能获得写锁。
使用读锁lock.readLock()可以提高程序运行效率,允许多个线程同时执行lock()方法后面的代码。
使用写锁lock.writeLock()的效果就是同一时间只允许一个线程执行lock()后面的代码。
3.乐观锁和悲观锁
悲观锁:
乐观的假设每次操作都可能会发生线程安全问题,每次去取数据的时候数据都已经被其它线程修改,于是每次读取数据的时候都给其上锁,其它线程想获取的时候就必须等待。比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。
乐观锁:乐观的假定每次操作都是安全的,不会发生数据的修改,于是不对其上锁,但是在更新的时候会判断一下在此期间其它线程有没有对其更新数据。
乐观锁实现(CAS):
采用一种“失败重试”的机制:
有三个值:
1.主内存中存放的被所有线程共享的值V
2.线程上次从内存读取的V值A,存放在线程的帧栈中,每个线程私有
3.需要写入内存中的修改后的V值B
判断V值和A值是否相等,
如果相等,则意味着没有被修改,此时将B值赋值给V值,完成修改
不相等,则返回V值,操作失败。
CAS的问题:(ABA)
A-B-A
解决办法:
1.在变量前面追加版本号,每次更新就把版本号增加1,则A-B-A就变成了1A-2B-3A。
2.atomic包下的AtomicStampedReference类:其compareAndSet方法首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用的该标志的值设置为给定的更新值。
java 中原子类的实现是依赖于CAS机制的。