diff --git a/week_03/62/ReentrantLock.md b/week_03/62/ReentrantLock.md new file mode 100644 index 0000000000000000000000000000000000000000..5a6a2fef48731928e4fceca1f5dc750e3ec2c6b5 --- /dev/null +++ b/week_03/62/ReentrantLock.md @@ -0,0 +1,63 @@ +##总结: +公平锁:加锁失败自动添加到队列尾巴 +非公平锁:加锁失败会继续尝试加锁,失败也会加到队列尾巴 + +##公平锁: +protected final boolean tryAcquire(int acquires) { + // 获取当前线程 + final Thread current = Thread.currentThread(); + // 获取变量state, 这个变量非常重要,全程主要是围绕这个变量来做事 + int c = getState(); + // 当变量state==0 的时候,表示当前锁是空闲的,可以获取 + if (c == 0) { + // 判断当前线程是不是等待最久的线程,就是说判断当前线程是不是在等待队列的第二个元素 + // 因为队列head是当前(之前)拥有锁的线程 + // 如果是,则表示等待时间最久 , 返回false , 表示没有线程比它等的更久 + if (!hasQueuedPredecessors() && + compareAndSetState(0, acquires)) { + // 设置当前执行线程(一个内部变量,为了后面的可重入功能)为 “当前线程” + setExclusiveOwnerThread(current); + return true; + } + } + // state !=0 , 并且当前线程==当前执行器线程(一个内部变量) + else if (current == getExclusiveOwnerThread()) { + // 对state赋值, 由此可以看出,ReentrantLock是一个可重入锁, + // 但是有一点,就是重入多少次,就必须要unlock多少次,以保证最终state==0 + int nextc = c + acquires; + if (nextc < 0) + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + +非公平锁: +final boolean nonfairTryAcquire(int acquires) { + final Thread current = Thread.currentThread(); + int c = getState(); + if (c == 0) { + // 大致逻辑和公平锁一致,唯一不同的是,这里并不会去判断当前线程是否是等待最久的线程。 + if (compareAndSetState(0, acquires)) { + setExclusiveOwnerThread(current); + return true; + } + } else if (current == getExclusiveOwnerThread()) { + int nextc = c + acquires; + if (nextc < 0) // overflow + throw new Error("Maximum lock count exceeded"); + setState(nextc); + return true; + } + return false; + } + +##AQS + AQS中的锁是可重入的,即同一个线程可以多次获取锁 + AQS中的锁也是独占的,即一个线程没有释放锁时,其他的线程不能获取锁 + 这里,对state的偏移量中的内存进行CAS操作,设置为1,表明第一次获取锁。 + AQS中,state是一个volatile变量,表示线程获取锁的次数,state为0, + 表示没有获取锁,state大于1,则表示重入锁获取的次数。执行完compareAndSetState + 第一次获取锁之后,执行setExclusiveOwnerThread,在AbstractOwnableSynchronizer + 类中设置成员变量Thread exclusiveOwnerThread为当前线程,表示这个线程独占了这个锁。 diff --git a/week_03/62/synchronized.md b/week_03/62/synchronized.md new file mode 100644 index 0000000000000000000000000000000000000000..d5ad85827d8495ed91ae287f376107f420a982e9 --- /dev/null +++ b/week_03/62/synchronized.md @@ -0,0 +1,7 @@ +总结: +synchronized:重量级锁,可参考java堆内存对象头里的内容,链接https://www.jianshu.com/p/3d38cba67f8b +实现加锁,有最开始的通过jvm调用内核,实现枷锁,改变为,在对象头中实现偏向锁,锁标记, +实现在jvm进行轻量级的加锁,提高效率。当轻量级锁自旋达到一定次数之后,自动升级为重量级锁。 + +和lock相比较,在线程数量相差很多的情况下,synchronized明显优于lock,lock适用于自旋,那线程占用的处理时间应该是越少越好, +所以这两种锁,在不同的情况下能发挥各自更好的性能,以及使用场景。 \ No newline at end of file diff --git a/week_03/62/volatile.md b/week_03/62/volatile.md new file mode 100644 index 0000000000000000000000000000000000000000..814f7a6d9e7c3f2cf9cee4f7029774d841f7fc01 --- /dev/null +++ b/week_03/62/volatile.md @@ -0,0 +1,5 @@ +总结: +volatile能保证可见性,有序性,可以保证部分原子性 +可见性:通过内存屏障实现 +有序性:在双重check的单例模式中可以体现有序性,避免生成多个实例 +原子性,能保证部分基础数据类型简单操作的原子性,long和double这样8个字节的并不能保证原子性 \ No newline at end of file diff --git "a/week_03/62/\345\206\205\345\255\230\346\250\241\345\236\213.md" "b/week_03/62/\345\206\205\345\255\230\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..07cd254c8dc7539666de3b1cb680d91675fe78a3 --- /dev/null +++ "b/week_03/62/\345\206\205\345\255\230\346\250\241\345\236\213.md" @@ -0,0 +1,4 @@ +参考文章: +https://blog.csdn.net/qq_34964197/article/details/80937147 +原子性,可见性,有序性 +内存屏障等,保证可见性 \ No newline at end of file