diff --git a/week_03/07/AbstractQueuedSynchronizer.md b/week_03/07/AbstractQueuedSynchronizer.md new file mode 100644 index 0000000000000000000000000000000000000000..c28f5baddeb9c40a166afb93fc52e8fdf62e9d97 --- /dev/null +++ b/week_03/07/AbstractQueuedSynchronizer.md @@ -0,0 +1,64 @@ +AbstractQueuedSynchronizer源码分析 +前言:AQS是基于链表实现的一个FIFO队列同步器,是Java中锁和同步器的一个基础框架。现在分析一下主要的一些类和方法 +1.Node类 + //链表节点Node,保存当前线程、前节点、后节点以及状态等信息 + static final class Node { + static final Node SHARED = new Node(); + static final Node EXCLUSIVE = null; + static final int CANCELLED = 1; + static final int SIGNAL = -1; + static final int CONDITION = -2; + static final int PROPAGATE = -3; + volatile int waitStatus; + volatile Node prev; + volatile Node next; + volatile Thread thread; + Node nextWaiter; + final boolean isShared() { + return nextWaiter == SHARED; + } + final Node predecessor() throws NullPointerException { + Node p = prev; + if (p == null) + throw new NullPointerException(); + else + return p; + } + Node() { // Used to establish initial head or SHARED marker + } + Node(Thread thread, Node mode) { // Used by addWaiter + this.nextWaiter = mode; + this.thread = thread; + } + Node(Thread thread, int waitStatus) { // Used by Condition + this.waitStatus = waitStatus; + this.thread = thread; + } + } +2.跟节点有关的变量 + private transient volatile Node head; //头节点 + private transient volatile Node tail; //尾节点 + //同步状态 + private volatile int state; + //这些变量的理性是用Unsafe类来操作的 + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final long stateOffset; + private static final long headOffset; + private static final long tailOffset; + private static final long waitStatusOffset; + private static final long nextOffset; + static { + try { + stateOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("state")); + headOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("head")); + tailOffset = unsafe.objectFieldOffset + (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); + waitStatusOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("waitStatus")); + nextOffset = unsafe.objectFieldOffset + (Node.class.getDeclaredField("next")); + } catch (Exception ex) { throw new Error(ex); } + } +3.因为这个类是一个抽象类,所以其它类要实现一个同步器的话,需要继承这个类,并实现里面特定的方法 diff --git a/week_03/07/ReentrantLock.md b/week_03/07/ReentrantLock.md new file mode 100644 index 0000000000000000000000000000000000000000..f6d4c28469258b0e57ac82a9f5a81af309984936 --- /dev/null +++ b/week_03/07/ReentrantLock.md @@ -0,0 +1,10 @@ +ReentrantLock源码分析 +前言:ReentrantLock实现自Lock接口,是一个可重入的锁,何为重入锁,是指一个线程获取锁之后再尝试获取锁时,会自动获取该锁 +1.首先看一看Lock接口里面的方法 + void lock(); //获取锁 + void lockInterruptibly() throws InterruptedException; //获取锁(可中断) + boolean tryLock(); //尝试获取锁,返回是否获取成功 + boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //在指定时间内获取锁 + void unlock(); //释放锁 + Condition newCondition(); //条件锁 +2.ReentrantLock里面实现两个锁,一个公平锁(FairSync),一个不公平锁(NonfairSync),都继承自Sync类。公平锁和非公平锁的实现主要一点就是获取锁时,看有没有线程在排队,公平锁看到有线程在排队就会等待,非公平锁就直接获取锁。另外就是一些Lock接口里面需要实现的方法,就不一一说了 \ No newline at end of file diff --git a/week_03/07/Semaphore.md b/week_03/07/Semaphore.md new file mode 100644 index 0000000000000000000000000000000000000000..e4397efd0d947c32d3e2f8ac97ab065d0b877c00 --- /dev/null +++ b/week_03/07/Semaphore.md @@ -0,0 +1,82 @@ +Semaphore源码分析 +前言:Semaphore用来控制同时访问特定资源的线程数量,也叫信号量。里面也有两种模式:公平模式和非公平模式,都是基于Sync类来实现,而Sync类继承自AbstractQueuedSynchronizer类 +1.Sync类分析 + abstract static class Sync extends AbstractQueuedSynchronizer { + private static final long serialVersionUID = 1192457210091910933L; + Sync(int permits) { //许可次数 + setState(permits); + } + final int getPermits() { + return getState(); + } + //非公平模式获取许可 + final int nonfairTryAcquireShared(int acquires) { + for (;;) { + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + //释放许可 + protected final boolean tryReleaseShared(int releases) { + for (;;) { + int current = getState(); + int next = current + releases; + if (next < current) // overflow + throw new Error("Maximum permit count exceeded"); + if (compareAndSetState(current, next)) + return true; + } + } + //减少许可 + final void reducePermits(int reductions) { + for (;;) { + int current = getState(); + int next = current - reductions; + if (next > current) // underflow + throw new Error("Permit count underflow"); + if (compareAndSetState(current, next)) + return; + } + } + //销毁许可 + final int drainPermits() { + for (;;) { + int current = getState(); + if (current == 0 || compareAndSetState(current, 0)) + return current; + } + } + } +2.非公平模式下获取许可调用的是Sync里的方法,默认的实现也是非公平模式的 + static final class NonfairSync extends Sync { + private static final long serialVersionUID = -2694183684443567898L; + NonfairSync(int permits) { + super(permits); + } + protected int tryAcquireShared(int acquires) { + return nonfairTryAcquireShared(acquires); + } + } +3.公平模式 + static final class FairSync extends Sync { + private static final long serialVersionUID = 2014338818796000944L; + FairSync(int permits) { + super(permits); + } + //如果还有其它的许可,则获取失败。 + protected int tryAcquireShared(int acquires) { + for (;;) { + if (hasQueuedPredecessors()) + return -1; + int available = getState(); + int remaining = available - acquires; + if (remaining < 0 || + compareAndSetState(available, remaining)) + return remaining; + } + } + } +4.总结:Semaphore用于限流场景,内部是基于AQS的共享锁来实现的 \ No newline at end of file diff --git "a/week_03/07/\347\220\206\350\256\272.md" "b/week_03/07/\347\220\206\350\256\272.md" new file mode 100644 index 0000000000000000000000000000000000000000..74adb050c4ef80218bd7554b9920b024c89a516e --- /dev/null +++ "b/week_03/07/\347\220\206\350\256\272.md" @@ -0,0 +1,22 @@ +1.Java内存模型 +java程序运行所需的内存是由虚拟机来分配,也就是JVM,所以直接看jvm所管理的内存包括哪些就行了。 +jvm所管理的内存包括下面几个运行时数据区域: + 1.程序计算器:线程所执行的字节码的行号指示器 + 2.java虚拟机栈:每个方法执行的时候,会创建一个栈帧,存储局部变量表、操作数栈、动态连接、方法出口等信息 + 3.本地方法栈:为虚拟机使用本地方法调用创建的栈 + 4.java堆:管理内存中最大的一块,被所有线程共享,用来存放对象实例 + 5.方法区:存储被JVM加载的类型信息、常量、静态变量、即时编译器编译的代码缓存数据 + 6.运行时常量池:属于方法区的一部分,用来存放编译期生成的各种字面量与符号引用 + 7.直接内存:不属于JVM规范中定义的内存区域,直接使用的物理内存,所以会出现内存溢出的异常 + +2.volatile +用来保证变量的可见性,禁止指令重排 +1.可见性:一个线程改变了变量的值,其他的线程能够立即看到修改的值。实现方法就是强制把CPU缓冲区的数据写到内存中,然后让缓存中相应的数据失效 +2.禁止指令重排:处理器为了提高程序运行效率,会对执行的指令进行重排,这就可能会打乱执行的顺序,所以会禁止指令重排 + +3.synchronized +在JVM中基于monitorenter和monitorexit这两个指令来实现的,用来解决多线程并发的问题。一次只允许一个线程对其进行操作,所以具有原子性和有序性,当一个线程退出后,会把变量刷新到内存中,所以具有可见性。当多个线程准备持有锁时,哪个线程优先级高,就会取得锁,所以synchronized是不公平锁 + + +4.分布式锁 +分布式锁我谈谈自己的看法,在实际项目中没有用过,但是要保证事务一致性,特别是保证多个微服务下的事务一致性,会加入消息队列和补偿机制去保证事务的一致性 \ No newline at end of file