自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

anlian523的博客

今天不学习,明天变垃圾,后天垃圾分类

  • 博客(243)
  • 资源 (1)
  • 论坛 (8)
  • 收藏
  • 关注

原创 JUC框架 源码解析系列文章目录 JDK8

前言笔者在接下来这段时间将对JUC框架内的重点内容进行深度解析,由于内容颇多,需要分成多篇文章,所以在这里列一个目录,方便大家翻阅。目录JUC框架的基础是CAS和自旋,而CAS则是利用Unsafe类提供的CAS操作,而原子类则依靠于CAS和自旋。下面几篇文章从源码分析JUC框架内的几个重要的原子类。JUC AtomicInteger源码解析 JDK8JUC AtomicIntegerArray源码解析 JDK8JUC AtomicStampedReference源码解析 JDK8AQS(A

2020-06-07 11:37:05 3523 8

原创 Python3读取、新建、追加写入Excel文件

直接安装Anaconda,它会自带xlrd模块,和openpyxl模块。我是用的是openpyxl模块,这个模块写入excel的好处是它不会改变原有excel的样式(最开始我用的是xlwt和xlutils,但是会改变原有样式)。

2021-04-15 21:03:09 126

原创 计算机网络 可靠数据传输原理——从rdt协议到GBN到SR

TCP处于运输层中,虽然下层协议——网络层协议是不可靠的,但TCP必须为它的上层提供一种可靠数据传输协议(reliable data transfer protocol)。这种协议提供的服务为:数据可以通过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会受到损坏或丢失,而且所有数据都是按照其发送顺序交付给接受方。

2021-02-28 16:32:44 297 2

原创 VSCode 复制代码时去掉样式/语法高亮/代码高亮

将图中位置去掉勾即可。在settings.json文件是这样的,没有这项的话默认是true的:{ something , "editor.copyWithSyntaxHighlighting": false}

2021-02-04 10:39:12 404 1

原创 你真的会写二分查找吗——变种二分查找

其实我已经写过一篇关于变种二分查找的博客了,但最近刷题时发现之前对变种二分查找的理解不够深刻,而且相比之前博客的实现,本文有了另一种不同的实现,虽然只是具体细节不一样。

2020-11-07 23:11:39 162

原创 LeetCode-SQL练习题总结(MySQL实现)

对LeetCode上的SQL练习题的免费部分进行了部分讲解,考虑大部分公司并没有升级到Mysql8,所以本文也没有使用窗口函数的解法(以后可以考虑补充,毕竟用了窗口函数解法就没有了通用性)。

2020-09-10 23:51:01 394

原创 JUC线程池 ScheduledThreadPoolExecutor源码解析 JDK8

ThreadPoolExecutor的功能已经很强大了,但却没有延时任务的功能。对于ScheduledThreadPoolExecutor,它的父类ThreadPoolExecutor所做的提交任务都是延时时间为0的延时任务。同时,它也提供了执行周期任务的功能。

2020-09-03 20:21:42 174

原创 JUC线程池 ThreadPoolExecutor源码解析 JDK8

ThreadPoolExecutor提供了管理线程的功能,它的最大好处在于能够复用线程,而不必在想要异步执行时用原始的new Thread().start()起线程。在构造ThreadPoolExecutor时通过给定不同的参数,可以得到不同效果的线程池。这样,使用者可以不用关心线程的管理,而专心于业务的编写。

2020-08-31 23:19:08 375

原创 JUC框架 CompletableFuture源码解析 JDK8

我们知道FutureTask实现了task异步执行,但对于执行结果的获取,如果异步执行还在进行中,那么线程只能get阻塞等待,或者轮询isDone,这两种方式都和我们开始实现异步的初衷相违背。所以就诞生了这个CompletableFuture,它的最大不同之处在于,通过提供回调函数的概念,把处理执行结果的过程也放到异步线程里去做。

2020-08-24 23:41:27 859 1

原创 JUC框架 FutureTask源码解析 JDK8

FutureTask的使用方法已经在上一篇进行了讲解,其实它和SynchronousQueue很像,执行task的线程是生产者,获取执行结果的线程是消费者,消费者阻塞的原因不是生产者还没来,是因为生产者还没有生产出来执行结果。只不过,这里只有一个生产者(FutureTask对象),却可以对应到多个消费者(对同一个FutureTask对象调用get的不同线程)。

2020-08-17 00:05:00 408

原创 JUC框架 从Runnable到Callable到FutureTask 使用浅析

本文旨在简单讲解Runnable、Callable、FutureTask这几个线程执行相关的接口和类。为后面FutureTask源码讲解作铺垫。

2020-08-15 19:49:39 179

原创 JUC集合类 SynchronousQueue源码解析 JDK8

SynchronousQueue其实就是LinkedTransferQueue的升级版,相同的是它们都作为生产者和消费者交互的通道,可以直接让生产者和消费者打交道。不同的是,SynchronousQueue做的更彻底,不去支持无关的共有操作(比如size()),只提供必要的入队出队方法。并且,SynchronousQueue提供了两种逻辑结构,栈和队列。理解LinkedTransferQueue是搞懂SynchronousQueue的前提。

2020-08-15 11:42:42 221

原创 JUC集合类 LinkedTransferQueue源码解析 JDK8

LinkedTransferQueue是一种特殊的无界阻塞队列,它提供一种Transfer的功能,用以保证生产者把数据传输给消费者。其他的普通队列,生产者是不需要关心消费者是否存在的,但现在的LinkedTransferQueue却需要保证生产者把数据确实传输给了消费者,才算是一次成功的入队操作,否则算作入队失败。

2020-08-09 22:38:05 283

原创 JUC集合类 DelayQueue源码解析 JDK8

DelayQueue是一个无界阻塞队列,它和PriorityBlockingQueue一样是一个优先队列,但区别在于队列元素只能放置Delayed对象,而且只有元素到期后才能将其出队。内部是一个最小堆,堆顶永远是最先“到期”的那个元素。如果堆顶元素没有到期,即使线程发现队列中有元素,也不能将其出队。DelayQueue需要依赖于元素对Delayed接口正确实现,即保证到期时间短的Delayed元素.compareTo(到期时间长的Delayed元素) < 0,这样可以让到期时间短的Delayed元素

2020-08-07 22:59:40 165

原创 JDK8 PriorityBlockingQueue(Collection<? extends E> c)构造器 源码解析

PriorityBlockingQueue的这个(Collection<? extends E> c)重载版本构造器的源码有几个地方有点难懂,但本文讲述内容不是PriorityBlockingQueue的重点理解内容,所以本文单独讲解。

2020-08-05 22:41:53 144

原创 JUC集合类 PriorityBlockingQueue源码解析 JDK8

PriorityBlockingQueue是一个无界阻塞队列,它的出队方式不再是FIFO,而是优先级高的先出队。其内部实现是最小堆,即堆顶元素是逻辑上最小的那个元素,也是最先出队的那个元素。简单的说,如果a.compareTo(b) < 0的话,那么a将先出队。

2020-08-04 22:03:07 180

原创 从小顶堆到堆排序——超详细图解——Python3实现

在简单选择排序中,每次选择会从待排序元素中找到最小值,但每次选择都需要遍历完剩余所有元素,而且在遍历时没有记录起来有用信息,这显得很浪费。而堆排序则利用了最小堆(或最大堆)的性质,每次选择最小值都会利用堆的数据结构来保存有用信息,即总是使得整个堆是一个最小堆,以便下一次选择时直接选择索引为0的节点就可以了。注意,本文使用到一个打印完全二叉树的算法方便我们观察整个堆的样子。具体做法是,新建一个printHeap.py,把这个算法除了测试代码都放进去。(不要误会,我绝对不是因为嫌画图麻烦才来写这个算法的

2020-08-01 23:54:54 565

原创 打印一颗基于数组的完全二叉树——Python3实现

最近在复习堆排序的内容,发现基于数组的堆虽然用起来很方便,但打印不方便。所以本文实现了一个简单美观的打印一颗基于数组的完全二叉树的算法(堆就是一种完全完全二叉树嘛,但实现最小堆一般是基于数组的)。

2020-08-01 17:37:39 217

原创 JUC集合类 LinkedBlockingDueue源码解析 JDK8

和ArrayBlockingQueue一样,使用一个Lock和两个Condition来控制并发和阻塞。因为两端都可以入队出队,所以用一个锁才能保证正确。和LinkedBlockingQueue不同的是,我们初始化时,连dummy node也没有。从first端移除的节点,next指针指向自身,以区别于first指向节点(next指针不会指向自身,可能为真实节点或null)。从last端移除的节点同理。

2020-07-30 23:55:45 398

原创 JUC集合类 LinkedBlockingQueue源码解析 JDK8

LinkedBlockingQueue是一种FIFO(first-in-first-out 先入先出)的有界阻塞队列,底层是单链表,也支持从内部删除元素。并发操作依赖于加锁的控制,支持阻塞式的入队出队操作。相比ArrayBlockingQueue的一个Lock,LinkedBlockingQueue使用了两个Lock,分别对应入队动作和出队动作,这便提高了并发量。

2020-07-29 23:58:02 337

原创 JDK8 ArrayBlockingQueue迭代器 源码解析

ArrayBlockingQueue的迭代器的整体设计很复杂,主要在于它需要去保证自己总是能保持 队首队尾索引,并以队首队尾索引为基础进行下一次的遍历。迭代器使用了一种“队首快照”的办法,用于发现 返回元素 相较与上一次快照时,实际上它已经被删除的情况。使得lastRet为REMOVE,从而让Itr#remove不会执行删除动作。还考虑内部删除节点的情景,这种情况需要 索引左移。

2020-07-26 19:59:14 364

原创 JUC集合类 ArrayBlockingQueue源码解析 JDK8

ArrayBlockingQueue是一种FIFO(first-in-first-out 先入先出)的有界阻塞队列,底层是数组,也支持从内部删除元素。并发操作依赖于加锁的控制,支持阻塞式的入队出队操作。正因为有界,所以才会阻塞。加锁实现完全依赖于AQS,需要读者比较熟悉AQS 独占锁的获取过程和AQS Condition接口的实现。对ArrayBlockingQueue的源码解析,更像是了解一次AQS的最佳实践。

2020-07-25 17:44:29 433

原创 JUC集合类 ConcurrentLinkedDueue源码解析 JDK8

ConcurrentLinkedDueue是一个无界的双端队列,它的并发操作是基于CAS的无锁实现,所以不会产生阻塞。要想理解ConcurrentLinkedDueue,先去理解了ConcurrentLinkedQueue才是快捷方式,因为它们二者使用的概念和函数实现的套路实际上都很类似。

2020-07-25 11:46:38 160

原创 JUC集合类 ConcurrentLinkedQueue源码解析 JDK8

ConcurrentLinkedQueue是一种FIFO(first-in-first-out 先入先出)的队列,底层是单链表,一般来说,队列只支持队尾入队、队头出队,但此类还支持从内部删除某个特定的节点。使用非阻塞算法来处理并发操作,这也意味着实现里充满了CAS和自旋。

2020-07-22 00:44:59 453 2

原创 JDK8 ConcurrentHashMap的Bug集锦

JDK8的ConcurrentHashMap并不是完美的,从https://bugs.openjdk.java.net/projects/JDK/issues上也可以看到JDK的很多Bug,当然,通过给concurrency-interest发邮件也可以和Doug Lea直接对话。最重要的是,知道了这些bug的存在,可以避免我们去分析这些不正确的代码的“正确性”。

2020-07-19 11:02:50 385

原创 JUC集合类 ConcurrentHashMap源码解析 JDK8
原力计划

ConcurrentHashMap是一种支持并发操作的HashMap,并发控制方面,它使用更小粒度的锁——对每个哈希桶的头节点加锁。虽然这样使得效率更高,能让读写操作最大程序的并发执行,但也造成了读写操作的一致性很弱,比如size()返回的大小可能已经与真实大小不一样,比如clear()调用返回后Map中却拥有着元素。JDK8的ConcurrentHashMap并不是完美,在阅读源码之前,建议先看看ConcurrentHashMap有些什么bug,以免在这些地方钻牛角尖。

2020-07-19 10:58:27 685

原创 ThreadLocalRandom#getProbe #advanceProbe浅析
原力计划

简单的说,一个线程的probe探针值,是一个hash值,它不会和其他线程重复(一定情况下)。ThreadLocalRandom的probe机制在线程数比较少,且probe移动次数也比较小时,是可以保证探针不重复的。但是不重复的情况指的是在int的范围内不重复,在有限的桶位面前,由于只取probe值的后几位bit,那么很大概率也会重复。

2020-07-12 14:02:02 719

原创 JUC集合类 ConcurrentSkipListMap源码解析 JDK8
原力计划

ConcurrentSkipListMap的实现是完全的无锁编程lock free。为了保证并发删除和插入正常执行,加入了marker机制,以及删除过程的三个步骤。base层和index层的头节点都是dummy节点,如果没有dummy节点,实现将会变得复杂。每个节点插入后,将新建的index层是完全随机的。如果新建层数超过了现有最大层数,那么新建层数则为最大层数+1。SkipList跳表使用空间换取时间,以得到查找效率。正因为插入节点的新建index层数是完全随机的,所以也使得实现更简单,整个跳表从

2020-07-06 22:38:10 317

原创 JUC集合类 CopyOnWriteArraySet源码解析 JDK8
原力计划

但CopyOnWriteArraySet的底层实现完全依赖了CopyOnWriteArrayList,它持有了一个CopyOnWriteArrayList类型的成员,很多方法的实现都是直接调用CopyOnWriteArrayList的同名方法。这意味着CopyOnWriteArraySet的底层实现不再是散列表的实现,而只是一个普通数组,只不过现在CopyOnWriteArraySet表现地像一个HashSet而已,不过这对于使用者来说已经足够了。

2020-06-27 17:46:58 322

原创 JUC集合类 CopyOnWriteArrayList源码解析 JDK8
原力计划

volatile + return操作/赋值操作,保证了数组成员的可见性和原子性。读操作不用加锁,直接获取数组成员。写操作需要加锁,并拷贝原数组成员。优点:保留了读操作的高性能。避免了并发修改抛出的异常。缺点:写操作太多时,将产生高内存消耗。因为需要拷贝出新数组。读操作不能保证看到最新的数据,即使写操作已经开始执行了。因为直到写操作执行setArray之前,读操作都无法看到最新数据。场景:读操作多,写操作少的场景。读操作允许看到非最新数据的场景。

2020-06-27 15:19:44 345

原创 JUC框架 ReentrantReadWriteLock源码解析 JDK8
原力计划

同步器的state被划分为两个部分,分别记录被拿走的读锁和写锁的总数。分别记录各个线程拿走的读锁的工作交给了各个线程自己,通过ThreadLocal实现。不仅写锁可以重入(这类似于ReentrantLock),读锁也可以重入。尝试获取写锁时,会因为其他写锁或任意读锁(包括自己)的存在,而进入阻塞等待的过程,抛入sync queue中去。尝试获取读锁时,会因为其他写锁(不包括自己的写锁)的存在,而进入阻塞等待的过程,抛入sync queue中去。读锁的非公平获取中,apparentlyFirstQu

2020-06-26 12:07:06 502 3

原创 ReentrantReadWriteLock的readerShouldBlock与apparentlyFirstQueuedIsExclusive 深入理解读锁的非公平实现
原力计划

readerShouldBlock的非公平实现,并不是完全的非公平实现(即直接返回false)。readerShouldBlock的不完全的非公平实现,是为了防止写锁无限等待。readerShouldBlock在一定概率下,防止了new reader的读锁获取动作,转而让new reader去sync queue中排队。

2020-06-26 09:48:35 606

原创 JUC框架 Semaphore源码解析 JDK8
原力计划

Semaphore的AQS子类是一个很标准的共享锁实现。获得信号量 == 减小AQS的state。释放信号量 == 增加AQS的state。共享锁的AQS子类实现方法需要自旋,这一点在Semaphore和CountDownLatch都有体现。独占锁的AQS子类实现方法不需要自旋。获得信号量失败一定是因为信号量已经减到0了,且获得失败就会阻塞。

2020-06-24 23:07:55 388

原创 JUC框架 CyclicBarrier源码解析 JDK8
原力计划

CyclicBarrier类似于CountDownLatch但又不同,在CyclicBarrier里,每个线程既要CountDown减小计数器,也要阻塞等待直到count为0(即等待线程到齐)。CyclicBarrier基于独占锁和条件队列而实现。CyclicBarrier可以重复使用,每有parties个线程到达barrier,开启新的一代。然后旧的一代线程就会相继从CyclicBarrier#await退出。CyclicBarrier实现了all-or-none breakage model的原则

2020-06-21 18:14:18 436

原创 JUC框架 CountDownLatch源码解析 JDK8
原力计划

CountDownLatch的使用场景:当某个量化为数字的条件被满足后,几个线程任务才可以同时开始执行。调用CountDownLatch#await的线程将等待条件被满足,条件满足后,调用CountDownLatch#await的若干线程将从同一个时间点继续执行。调用CountDownLatch#countDown,让量化为数字的条件减一。调用CountDownLatch#await的线程,和调用CountDownLatch#countDown的线程,是两类线程,并无关系。唤醒阻塞在await的若干

2020-06-20 11:23:06 448

原创 interrupt()中断对LockSupport.park()的影响
原力计划

park调用后一定会消耗掉permit,无论unpark操作先做还是后做。如果中断状态为true,那么park无法阻塞。unpark会使得permit为1,并唤醒处于阻塞的线程。interrupt()会使得中断状态为true,并调用unpark。sleep() / wait() / join()调用后一定会消耗掉中断状态,无论interrupt()操作先做还是后做。

2020-06-15 22:32:55 902 2

原创 AQS深入理解系列(四)Condition接口的实现
原力计划

一个新设计的出现,总是为了替换现有的略有不足的设计。而Condition接口的出现,是为了代替监视器锁的wait/notify机制,提供更强大的功能。先简单说明一下它们之间的相同之处,以便之后更好地理解Condition接口的实现:调用wait()的线程必须已经处于同步代码块中,换言之,调用wait()的线程已经获得了监视器锁;调用await()的线程则必须是已经获得了lock锁。执行wait()时,当前线程会释放已获得的监视器锁,进入到该监视器的等待队列中;执行await()时,当前线程会释放已获

2020-06-14 18:59:43 749

原创 AQS深入理解系列(三)共享锁的获取与释放
原力计划

独占锁是线程独占的,同一时刻只有一个线程能拥有独占锁,AQS里将这个线程放置到exclusiveOwnerThread成员上去。共享锁是线程共享的,同一时刻能有多个线程拥有共享锁,但AQS里并没有用来存储获得共享锁的多个线程的成员。如果一个线程刚获取了共享锁,那么在其之后等待的线程也很有可能能够获取到锁。但独占锁不会这样做,因为锁是独占的。当然,如果一个线程刚释放了锁,不管是独占锁还是共享锁,都需要唤醒在后面等待的线程。

2020-06-08 10:26:13 1221 8

原创 AQS深入理解系列(二) 独占锁的释放过程
原力计划

首先会尝试设置状态从小于0变成0。一般可以这样认为,如果head的状态为0,代表head后继线程即将被唤醒,或者已经被唤醒。如果遇到s == null,说明我们遇到一种中间状态,next指针还没有指好。如果遇到s.waitStatus > 0,说明head后继刚取消了。这两种情况,都需要从队尾的prev往前找。关于prev的有效性,已经在上一篇博客讲过了。注意循环条件t != null && t != node,它会从队尾一直往前找,直到t是null或t已经到达了node。一般情况下,不会出现t !=

2020-06-04 23:44:02 608

原创 AQS深入理解系列(一) 独占锁的获取过程
原力计划

对于独占锁,AQS的state代表代表锁的状态,为0代表没有线程持有锁,非0代表有线程持有了锁。获得了锁的线程会将自己设置为exclusiveOwnerThread。addWaiter负责new出一个包装当前线程的node,enq负责将node添加到队尾,如果队尾为空,它还负责添加dummy node。acquireQueued是整个获取锁过程的核心,这里是指它的那个死循环。一般情况下,每次循环做的事就是:尝试获取锁,获取锁失败,阻塞,被唤醒。如果某一次循环获取锁成功,那么之后会返回到用户代码调用处。

2020-06-03 00:03:19 1749 3

ArcGIS 10.1 破解文件.rar

ArcGIS 10.1 破解文件。在你安装完ArcGIS 10.1 for Desktop.iso后使用的。

2019-05-25

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人 TA的粉丝

提示
确定要删除当前文章?
取消 删除