自定义博客皮肤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的博客

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

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

首先会尝试设置状态从小于0变成0。一般可以这样认为,如果head的状态为0,代表head后继线程即将被唤醒,或者已经被唤醒。 如果遇到s == null,说明我们遇到一种中间状态,next指针还没有指好。如果遇到s.waitStatus > 0,说明head后继刚取消了。这两种情况,都需要从...

2020-06-04 23:44:02 50 0

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

对于独占锁,AQS的state代表代表锁的状态,为0代表没有线程持有锁,非0代表有线程持有了锁。 获得了锁的线程会将自己设置为exclusiveOwnerThread。 addWaiter负责new出一个包装当前线程的node,enq负责将node添加到队尾,如果队尾为空,它还负责添加dummy ...

2020-06-03 00:03:19 99 0

原创 AQS深入理解 shouldParkAfterFailedAcquire源码分析 状态为0或PROPAGATE的情况分析
原力计划

检测到0后,一定要设置成SIGNAL的原因: 设置前驱状态为SIGNAL,以便当前线程阻塞后,前驱能根据SIGNAL状态来唤醒自己。(具体看章节释放锁后,唤醒head后继的条件) 设置成SIGNAL后会返回false的原因: 返回false后,下一次循环开始,会重新获取node的前驱,前驱如果...

2020-05-31 16:28:37 121 0

原创 AQS深入理解 doReleaseShared源码分析 JDK8
原力计划

doReleaseShared会尝试唤醒 head后继的代表线程,如果线程已经唤醒,则仅仅设置PROPAGATE状态。 上一条的“尝试唤醒 head后继的代表线程”和“设置PROPAGATE状态”都是CAS操作,如果CAS失败,循环会马上continue并再次尝试。 当检测到局部变量h与当前最新h...

2020-05-24 22:29:42 165 0

原创 AQS深入理解 setHeadAndPropagate源码分析 JDK8
原力计划

如果propagate > 0不成立,而h.waitStatus < 0成立。这说明旧head的status<0。但如果你看doReleaseShared的逻辑,会发现在unparkSuccessor之前就会CAS设置head的status为0的,在unparkSuccessor...

2020-05-24 19:12:14 137 1

原创 Java并发 volatile可见性的验证
原力计划

加了同步块,子线程会退出。 这是因为synchronized具体过程是: 获得同步锁; 清空工作内存; 从主内存拷贝对象副本到工作内存; 执行代码(计算或者输出等); 刷新主内存数据; 释放同步锁。 简单的说,synchronized进入时,会将 主内存中最新的变量,拷贝进 自己线程 的工作内...

2020-05-17 21:35:42 85 0

原创 AQS深入理解 hasQueuedPredecessors源码分析 JDK8
原力计划

分析hasQueuedPredecessors的返回判断。首先要知道,hasQueuedPredecessors返回true代表有别的线程在CHL队列中排了当前线程之前;返回false代表当前线程处于CHL队列的第一个线程。 分析h != t返回false的情况。此时hasQueuedPrede...

2020-05-17 18:13:35 205 3

原创 JUC AtomicIntegerArray源码解析 JDK8
原力计划

相比其他原子类,原子数组类AtomicIntegerArray,它的成员不再是volatile的,而是final的。从设计上来讲,作为原子数组类的数组成员初始化后,确实也不应该被修改引用了。 计算数组元素的地址偏移时,需要两个值,base和元素索引。 get/set函数不能像其他原子类一样,get...

2020-05-10 21:21:33 80 0

原创 JUC AtomicStampedReference源码解析 JDK8
原力计划

最终调用Unsafe的compareAndSwapObject方法时,是不关心版本号的。compareAndSwapObject只关心是不是同一个对象。(但这样不会造成问题) 虽然根据上一条,感觉可能会有问题。但是由于静态内部类Pair每次都会新构造对象出来,即使T reference, int ...

2020-05-10 18:08:51 60 0

原创 JUC AtomicInteger源码解析 JDK8

AtomicInteger类通过volatile语义加上CAS操作,使得对AtomicInteger的操作实现了一种非阻塞同步,从而保证了线程安全。非阻塞在于它没有使用synchronized或者Lock,而是循环加CAS,既然是循环执行,那么肯定没有阻塞线程,也就没有切换线程所带来的消耗。

2020-05-10 15:52:05 72 0

原创 Java编程思想 并发 新类库中的构件demo浅析
原力计划

每个Horse线程都会阻塞在await处,但每阻塞一次 CyclicBarrier对象的计数器都会减少1,当7个Horse线程都执行了await,这个计数器便减小到了0。然后会执行CyclicBarrier构造器中的匿名线程,当匿名线程执行完毕后,7个Horse线程才会重新从await处唤醒。同样...

2020-05-08 23:13:50 58 0

原创 听说你看过ThreadLocal源码,来面试下这几个问题
原力计划

ThreadLocal的用途 ThreadLocal用来给各个线程提供线程隔离的局部变量。使用很简单,通过调用同一个ThreadLocal对象的get/set方法来读写这个ThreadLocal对象对应的value,但是线程A set值后,不会影响到线程B之后get到的值。 ThreadLoca...

2020-04-19 22:54:00 262 0

原创 JUC ThreadLocal源码行级解析 JDK8
原力计划

ThreadLocal看类名就是线程本地变量的意思。从使用上来说,如果定义了一个ThreadLocal,那么各个线程针对这个ThreadLocal进行get/set都是线程独立的,也就是说,是线程隔离的本地变量。 从实现上来说,每个线程在运行过程中都可以通过Thread.currentThrea...

2020-04-19 20:00:40 143 0

原创 Java 生产者消费者案例——等待唤醒机制、虚假唤醒

wait() \ notify() \ notifyAll()这三方法必须在synchronized方法或synchronized同步代码块中执行,因为这样就说明currentThread已经获得了对象的monitor。 wait()使得当前线程释放已获得的对象monitor,并陷入一种等待。这种...

2020-04-11 19:53:39 324 0

原创 【LeetCode.53】 最大子序和——以及变种 返回开始结束索引

不用新建一个dp数组了,直接在nums数组上覆盖就好,因为无后效性,当前元素遍历后,就可以覆盖为dp[i]的值。 dp[0]的值,初始时,就是确定的,因为只有一个元素的数组,它的唯一的子序列就是它自己。 从递推公式dp[i+1] = max(nums[i+1], dp[i]+nums[i+1])可...

2020-04-09 22:58:28 123 0

原创 你真的会写二分查找吗——分析二分查找变种代码
原力计划

我们已经知道循环条件是left <= right,所以循环结束条件是left > right,且肯定是right = left -1。而且在key存在的情况下,left 和 right 肯定有一个落在边缘key上(边缘key是指,多个key时的最左key或最右key);如果key不存在...

2020-04-05 00:16:31 165 0

原创 【LeetCode.167】 两数之和 II - 输入有序数组

双端指针如果是用来遍历单个元素时,肯定没有问题的,最终每个元素都能遍历到。但此题实际是,要求我们去遍历元素的组合,即两个元素的组合,那么双端指针在遍历过程中,肯定不能遍历到所有组合情况,或者说,在遍历过程中,它会选择方向,适当排除掉某些情况。

2020-04-04 13:07:49 72 0

原创 【LeetCode.27】 移除元素

我们将算法结束后关心的前n个元素,称为压实数组。因为整个过程看起来就是在往左压实。 compactIndex代表即将加入压实数组的那个元素应该赋值的索引。所以初始时,compactIndex为0,因为初始时一个非val元素都没有得到确认。 cursor即为遍历指针。 当遍历元素非val时,将其赋值...

2020-04-02 23:59:04 111 0

原创 【LeetCode.26】 删除排序数组中的重复项

遍历数组,如果cursor所在元素与compareNum相同,那么只增加cursor。 如果cursor所在元素与compareNum不同,那么除了增加cursor外,还需要压实操作:把cursor所在元素赋值给 compactIndex下标元素,更新compareNum为 cursor所在元素(...

2020-04-01 23:36:18 106 0

原创 Java反射 获得Class对象的五种方法

通过Class.forName(类名)获得。但这种方式获得的Class对象的泛型类型只能是通配符的,从下面的两行注释代码可知,要想获得更具体的泛型类型时,都会编译报错。 通过对象.getClass()获得。这种方式获得的Class对象的泛型类型,虽然比上一种更加具体,可以是Class<? e...

2020-03-29 14:27:34 386 0

原创 Java序列化 Serializable和Externalizable浅析

Serializable接口 ObjectOutputStream#writeObject() 与 NotSerializableException ObjectInputStream#readObject() 与 ClassNotFoundException Serializable接口的类,不...

2020-03-28 17:59:14 143 0

原创 【LeetCode.1】两数之和

最重要的,这道题必须能想到target - current,才能得到最优解。current代表当前正在遍历的元素,令target - current = exist,那么exist就是已经遍历过的元素。如果target - current是已经遍历过的,那么说明两个目标就找到了。 同样重要的,遍历...

2020-03-27 00:19:03 254 0

原创 Java NIO 注册事件的正确姿势 以及对attach()的理解

当你注册channel给Selector的时候,会把一个key与channel关联起来。 key包含了每一个channel所感兴趣的事件,即图中的key就是一个SelectionKey实例。所以api文档里的key set包含了每一个channel关联的key。 而api文档里的selected-...

2020-03-22 14:38:06 344 0

原创 使用NIO从阻塞式通信到非阻塞式通信——各种示例循序渐进带你理解

当客户端执行完SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));这句后,服务端打印出了after BlockingServer accept before ...

2020-03-22 13:58:34 166 0

原创 Java NIO中一方断开连接或shutdownOutput 另一方不断READ事件

当canReadChannel.read(buf)抛出异常时,则是连接断开了。需要关闭channel,且取消SelectionKey。 之前的测试,通过停止运行程序来关闭SocketChannel,其实就相当于调用SocketChannel.close()方法,然后另一方就会不断收到READ事件。...

2020-03-21 16:38:13 245 0

原创 SocketChannel 使用open或connect/finishConnect

调用connect后除非连接能马上建立能返回true,否则就返回false。连接是否能建立要通过后续的finishConnect判断。 在select循环里,先检测SelectionKey是否isConnectable为true,如果是则进入分支,再执行SocketChannel.finishCo...

2020-03-21 14:35:31 320 0

原创 Java 用NIO实现一个聊天室(多人聊天、单人聊天)

这两行代码由于前后发送,所以client这个channel会先后收到 昵称验证通过 和 推送上线 的消息,如果tcp在传输过程中足够快,那么客户端在一次read事件中,会把两次消息一次性读出来。而由于这个代码写的比较简陋,在tcp的传输内容上并没有建立起足够安全的内容协议(比如消息与消息用特定的分...

2020-03-19 23:26:04 130 0

原创 JDK8 NIO.Buffer源码解析 深入理解clear flip rewind compact

在NIO体系中,Buffer至关重要,因为我们通过Buffer和Channel打交道,事实上我们永远无法和Channel直接打交道,只能通过Buffer作为媒介。如果把Channel比喻为蕴含着数据的矿山,那么Buffer就是用来装数据的矿车,我们只能把矿车送进矿车,并期待矿车回来时能塞满了来自矿...

2020-02-23 17:19:51 584 0

原创 PrintStream和PrintWriter的区别和联系

其实PrintStream也很low,观察它的构造器可以发现它竟然是靠BufferedWriter来驱动的(这看起来和上面贴的PrintWriter的构造器里的逻辑一样,这里指装饰器的装饰过程)也就是说,这句new PrintStream( new BufferedOutputStream( ne...

2020-02-14 19:52:51 438 0

原创 Java BIO体系详解

输入流是将数据从文件中流向内存;输出流则是将数据从内存中流向文件。 输入流能做的事情无非是:将文件中的数据放入java的数据类型中(比如byte、char、short、int)。 输出流能做的事情无非是:将java数据类型中的数据放入文件中。 对于程序来说:输入流是有能力产出数据的流,输出流是有能...

2020-02-14 19:51:05 497 0

原创 PrintWriter装饰FileWriter后,对字符串的默认编码方式

new PrintWriter( new BufferedWriter( new FileWriter("BasicFileOutput.out")))这句代码,外面的PrintWriter和BufferedWriter都只是为了装饰,为了拓展功能,它们只是在和程序的内存打交道...

2020-02-13 21:18:32 409 0

原创 从String获得ByteBuffer、从ByteBuffer获得CharBuffer的正确姿势

cb.toString()时,认为cb对象持有的ByteBuffer成员的字节数组都是UTF-16字符集转换而来的字节,同时它又利用了当Unicode码<0x10000时,UTF-16字符集对应字节与Unicode码一样。而java的char类型就是使用二字节长度的Unicode码作为底层存...

2020-01-27 00:41:38 757 0

原创 Java源码分析 ByteBuffer.asCharBuffer打印字符串乱码原因

如上图可见cb对象是一个ByteBufferAsCharBufferB实例,它持有一个ByteBuffer类型的对象(实际上就是那个bb对象),也就是说,打印CharBuffer时,它的实际数据来源于它持有的那个ByteBuffer类型的对象。

2020-01-26 15:24:47 626 0

原创 Java 遍历目录下的所有文件(深度优先遍历,宽度优先遍历)

只要是调用了递归方法体,传进来的startDir必定是一个目录(isDirectory返回true),这是由循环中调用递归的前提判断来保证的。 在循环中,如果发现循环变量item是一个当前目录下的文件,那么执行else分支,不会调用到递归函数;如果发现循环变量item是一个当前目录下的子目录,那么...

2020-01-15 22:04:16 1063 0

原创 JDK8 HashMap源码行级解析 红黑树操作 史上最全最详细图解

源码面前,了无秘密。 本文对HashMap红黑树部分的1790~2388行源码进行了详细解析。 本文将会在代码里把注释写得尽可能地全,以理解源码的各个细节,而在源码片段后则将进行提纲挈领的总结性讲解,在行文中可能穿插大量的图片以配合讲解,因为红黑树这种东西真的很需要看图来理解。本文既适合已经阅...

2020-01-12 17:54:30 6239 5

原创 听说你看过HashMap源码,来面试下这几个问题

HashMap的主要成员都有哪些? Entry<K,V>[] table。这个Entry类型的数组存储了HashMap的真正数据。 size大小。代表HashMap内存储了多少个映射。 capacity容量。实际上HashMap没有一个成员叫capacity,它是作为table这个数组...

2020-01-05 00:12:37 1544 1

原创 JDK8 HashMap源码行级解析 史上最全最详细解析

源码面前,了无秘密。 除了红黑树部分,本文对HashMap的1789行源码进行了详细解析。 本文将会在代码里把注释写得尽可能地全,以理解源码的各个细节,而在源码片段后则将进行提纲挈领的总结性讲解。本文既适合已经阅读过部分源码的同学,可以来这里查漏补缺,或解决疑惑;也适合从头开始阅读HashMa...

2020-01-04 20:55:13 1271 0

原创 深入理解HashMap:那些巧妙的位操作

capacity永远为2的幂 我们都知道HashMap的容量永远为2的幂,而HashMap没有一个成员名叫capacity,capacity是作为table这个数组的size而隐式存在的。 当用户构造HashMap时给了一个奇怪的容量时,会通过this.threshold = tableSizeF...

2020-01-02 23:45:19 890 0

原创 JDK8 HashMap源码 clone解析

分析源码 Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned. 英文注释已经说了这个一个浅拷贝操作,但到底浅到什么程度呢,接下来本文将进行详细分析。 ...

2020-01-02 21:49:51 598 0

原创 走进科学之——为何刚初始化的HashMap的entrySet不为null

疑团重重 当你调试以下代码时,你会发现oldMap的entrySet不为null: HashMap<Object,Integer> oldMap = new HashMap<Object,Integer>(); System.out.println();//此处打断点 ...

2020-01-02 20:42:29 733 1

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