java实现锁的三种方式
volatile关键字
volatile用于修饰的变量,属于JUC层面的锁,在多线程访问的情况下,不会出现脏读,所有读请求都能读到更新后的数据。它是通过读写屏障去实现锁的效果,就是我更新完数据,会强制去更新主缓存和各级缓存的数据。 如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。
public static volatile int i
= 1;
synchronize关键字
这个同样属于JUC层面,编译时,会创建一个monitor,通过monitor去实现原子操作。灵活性更高。详情见我上一篇博客。
https://blog.csdn.net/weixin_38608225/article/details/108912437
Lock对象
这个是属于JDK沉默提供的锁,有 ReentranLock(重入锁),ReentrantReadWriteLock(读写锁),FairLock(公平锁),UnfairLock(非公平锁)等供选择,且提供众多API供我们监视和影响锁的状态。
可重入锁
static class ReenLock extends Thread{
private Lock lock
;
private String name
;
public ReenLock(Lock lock
,String name
) {
this.lock
= lock
;
this.name
= name
;
}
@Override
public void run() {
lock
.lock();
System
.out
.println("ReenLock doing!" + name
);
try {
TimeUnit
.SECONDS
.sleep(1);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
lock
.unlock();
}
}
读写锁
static class ReadLock extends Thread{
private ReentrantReadWriteLock lock
;
private String name
;
public ReadLock(ReentrantReadWriteLock lock
, String name
) {
this.lock
= lock
;
this.name
= name
;
}
@Override
public void run() {
lock
.readLock().lock();
try {
System
.out
.println("read lock succ! "+ name
);
TimeUnit
.SECONDS
.sleep(2);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
lock
.readLock().unlock();
}
}
static class WriteLock extends Thread{
private ReentrantReadWriteLock lock
;
private String name
;
public WriteLock(ReentrantReadWriteLock lock
, String name
) {
this.lock
= lock
;
this.name
= name
;
}
@Override
public void run() {
lock
.writeLock().lock();
try {
System
.out
.println("write lock succ! "+ name
);
TimeUnit
.SECONDS
.sleep(2);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
lock
.writeLock().unlock();
}
}
main方法 测试用
public static void main(String
[] args
) {
Lock lock
= new ReentrantLock();
for (int i
= 0; i
< 10; i
++) {
new ReenLock(lock
,"thread" + i
).start();
}
System
.out
.println("==================================");
ReentrantReadWriteLock rwLock
= new ReentrantReadWriteLock();
for (int i
= 0; i
< 10; i
++) {
new ReadLock(rwLock
,"thread" + i
).start();
new WriteLock(rwLock
,"thread" + i
).start();
}
}
锁的实现原理
专有名词
CAS:全称(CompareAndSetState)原子性操作的思维,通过验证期望值和实际结果值的一致情况来确保原子性操作的成功性。入参两个,一个是实际参数用于程序运算出结果的依据;一个是期望值,希望程序算出那个结果才是有效的。如果结果和期望一致,才算执行成功,不一致则不成功。 好比:你拿一块钱想买两个肉包子,结果老板一块钱卖给你4个,你就不干了。
AQS:全称AbstractQueueSynchronizer,队列同步器,构建锁和处理锁的基础框架。用于存放竞争不到锁的线程队列,内部结构是个双向链表,且是FIFO。提供获取状态、设置状态、还有cas操作。 当获取到同步器的元素,会成为链表的头元素,处理完会释放锁,由剩余的元素通过自旋去争抢,争抢到则变成新的头元素。
Condition:简单来说就是一个执行队列,将AQS中获取到锁的进程放入Condition队列中去执行。
参考资料:
https://www.cnblogs.com/barrywxx/p/8678698.html 特别感谢这个大神的博客,很容易理解