![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
并发编程
文章平均质量分 95
知识记录者-vincent
这个作者很懒,什么都没留下…
展开
-
AQS 在 CountDownLatch 等类中的应用原理是什么?
AQS 用法讲一下 AQS 的用法。如果想使用 AQS 来写一个自己的线程协作工具类,通常而言是分为以下三步,这也是 JDK 里利用 AQS 类的主要步骤第一步,新建一个自己的线程协作工具类,在内部写一个 Sync 类,该 Sync 类继承 AbstractQueuedSynchronizer,即 AQS; 第二步,想好设计的线程协作工具类的协作逻辑,在 Sync 类里,根据是否是独占,来重写对应的方法。如果是独占,则重写 tryAcquire 和 tryRelease 等方法;如果是非独占,则原创 2020-09-21 21:20:37 · 114 阅读 · 0 评论 -
AQS 的内部原理是什么样的?
AQS 内部原理解析AQS 最核心的三大部分就是状态、队列和期望协作工具类去实现的获取/释放等重要方法state 状态状态 state,如果我们的 AQS 想要去管理或者想作为协作工具类的一个基础框架,那么它必然要管理一些状态,而这个状态在 AQS 内部就是用 state 变量去表示的。它的定义如下/** * The synchronization state. */private volatile int state;而 state 的含义并不是一成不变的,它会根据具体实现原创 2020-09-21 21:03:01 · 209 阅读 · 0 评论 -
为什么需要 AQS?AQS 的作用和重要性是什么?
AQS 的重要性我们先来介绍一下 AQS(AbstractQueuedSynchronizer)的重要性,来看看 AQS 被用在了哪些类里面如图所示,AQS 在 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、ThreadPoolExcutor 的 Worker 中都有运用(JDK 1.8),AQS 是这些类的底层原理学习 AQS 的思路我们大多数的程序员都是业务开发者,而不是 JDK 开发者,所以平时并不需要自原创 2020-09-21 20:44:15 · 2660 阅读 · 3 评论 -
为什么 String 被设计为是不可变的?
String 是不可变的在 Java 中,字符串是一个常量,我们一旦创建了一个 String 对象,就无法改变它的值,它的内容也就不可能发生变化(不考虑反射这种特殊行为)举个例子,比如我们给字符串 s 赋值为“vincent”,然后再尝试给它赋一个新值,正如下面这段代码所示String s = "vincent";s = "vin";看上去好像是改变了字符串的值,但其背后实际上是新建了一个新的字符串“vin”,并且把 s 的引用指向这个新创建出来的字符串“vin”,原来的字符串对象“v原创 2020-09-20 19:43:01 · 126 阅读 · 0 评论 -
为什么加了 final 却依然无法拥有“不变性”?
什么是不变性如果对象在被创建之后,其状态就不能修改了,那么它就具备“不变性”public class Person { final int id = 1; final int age = 18;}如果我们创建一个 person 对象,那么里面的属性会有两个,即 id 和 age,并且由于它们都是被 final 修饰的,所以一旦这个 person 对象被创建好,那么它里面所有的属性,即 id 和 age 就都是不能变的。我们如果想改变其中属性的值就会报错,代码如下所示p原创 2020-09-20 18:35:20 · 273 阅读 · 0 评论 -
final 的三种用法是什么?
final 的作用final 是 Java 中的一个关键字,简而言之,final 的作用意味着“这是无法改变的”。不过由于 final 关键字一共有三种用法,它可以用来修饰变量、方法或者类,而且在修饰不同的地方时,效果、含义和侧重点也会有所不同final 修饰变量作用关键字 final 修饰变量的作用是很明确的,那就是意味着这个变量一旦被赋值就不能被修改了,也就是说只能被赋值一次,直到天涯海角也不会“变心”。如果我们尝试对一个已经赋值过 final 的变量再次赋值,就会报编译错误/**原创 2020-09-20 18:16:02 · 2587 阅读 · 0 评论 -
经典的哲学家就餐问题
问题描述哲学家就餐问题也被称为刀叉问题,或者吃面问题。我们先来描述一下这个问题所要说明的事情,这个问题如下图所示有 5 个哲学家,他们面前都有一双筷子,即左手有一根筷子,右手有一根筷子。当然,这个问题有多个版本的描述,可以说是筷子,也可以说是一刀一叉,因为吃牛排的时候,需要刀和叉,缺一不可,也有说是用两把叉子来吃意大利面。这里具体是刀叉还是筷子并不重要,重要的是必须要同时持有左右两边的两个才行,也就是说,哲学家左手要拿到一根筷子,右手也要拿到一根筷子,在这种情况下哲学家才能吃饭为什么选择哲学原创 2020-09-20 17:45:32 · 6738 阅读 · 0 评论 -
有哪些解决死锁问题的策略?
线上发生死锁应该怎么办如果线上环境发生了死锁,那么其实不良后果就已经造成了,修复死锁的最好时机在于“防患于未然”,而不是事后补救。就好比发生火灾时,一旦着了大火,想要不造成损失去扑灭几乎已经不可能了。死锁也是一样的,如果线上发生死锁问题,为了尽快减小损失,最好的办法是保存 JVM 信息、日志等“案发现场”的数据,然后立刻重启服务,来尝试修复死锁。为什么说重启服务能解决这个问题呢?因为发生死锁往往要有很多前提条件的,并且当并发度足够高的时候才有可能会发生死锁,所以重启后再次立刻发生死锁的几率并不是很大,当原创 2020-09-19 14:53:30 · 1076 阅读 · 0 评论 -
如何用命令行和代码定位死锁?
命令:jstack这个命令叫作 jstack,它能看到我们 Java 线程的一些相关信息。如果是比较明显的死锁关系,那么这个工具就可以直接检测出来;如果死锁不明显,那么它无法直接检测出来,不过我们也可以借此来分析线程状态,进而就可以发现锁的相互依赖关系,所以这也是很有利于我们找到死锁的方式首先,我们运行一下必然发生死锁的MustDeadLock类/***描述:必定死锁的情况*/publicclassMustDeadLockimplementsRunnable{...原创 2020-09-19 14:32:03 · 510 阅读 · 0 评论 -
发生死锁必须满足哪 4 个条件?
要想发生死锁有 4 个缺一不可的必要条件第 1 个叫互斥条件,它的意思是每个资源每次只能被一个线程(或进程,下同)使用,为什么资源不能同时被多个线程或进程使用呢?这是因为如果每个人都可以拿到想要的资源,那就不需要等待,所以是不可能发生死锁的第 2 个是请求与保持条件,它是指当一个线程因请求资源而阻塞时,则需对已获得的资源保持不放。如果在请求资源时阻塞了,并且会自动释放手中资源(例如锁)的话,那别人自然就能拿到我刚才释放的资源,也就不会形成死锁第 3 个是不剥夺条件,它是指线程已获得的资源..原创 2020-09-19 14:17:53 · 1897 阅读 · 0 评论 -
死锁的例子演示
死锁是什么?有什么危害?死锁一定发生在并发场景中。我们为了保证线程安全,有时会给程序使用各种能保证并发安全的工具,尤其是锁,但是如果在使用过程中处理不得当,就有可能会导致发生死锁的情况互不相让死锁是一种状态,当两个(或多个)线程(或进程)相互持有对方所需要的资源,却又都不主动释放自己手中所持有的资源,导致大家都获取不到自己想要的资源,所有相关的线程(或进程)都无法继续往下执行,在未改变这种状态之前都不能向前推进,我们就把这种状态称为死锁状态,认为它们发生了死锁。通俗的讲,死锁就是两个或多个线程(原创 2020-09-19 13:11:51 · 3607 阅读 · 0 评论 -
CAS 有什么缺点?
ABA 问题CAS 最大的缺点就是 ABA 问题决定 CAS 是否进行 swap 的判断标准是“当前的值和预期的值是否一致”,如果一致,就认为在此期间这个数值没有发生过变动,这在大多数情况下是没有问题的但是在有的业务场景下,我们想确切知道从上一次看到这个值以来到现在,这个值是否发生过变化。例如,这个值假设从 A 变成了 B,再由 B 变回了 A,此时,我们不仅认为它发生了变化,并且会认为它变化了两次在这种场景下,我们使用 CAS,就看不到这两次的变化,因为仅判断“当前的值和预期的值是否一致”原创 2020-09-19 12:52:03 · 512 阅读 · 0 评论 -
CAS 和乐观锁的关系,什么时候会用到 CAS?
并发容器DougLea 大神在JUC包中大量使用了CAS技术,该技术既能保证安全性,又不需要使用互斥锁,能大大提升工具类的性能。通过两个例子来展示 CAS 在并发容器中的使用情况案例一:ConcurrentHashMap先来看看并发容器 ConcurrentHashMap 的例子,我们截取部分 putVal 方法的代码final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value...原创 2020-09-19 12:12:41 · 717 阅读 · 0 评论 -
什么是 CAS ?
CAS 简介它的英文全称是 Compare-And-Swap,中文叫做“比较并交换”,它是一种思想、一种算法在多线程的情况下,各个代码的执行顺序是不能确定的,所以为了保证并发安全,我们可以使用互斥锁。而 CAS 的特点是避免使用互斥锁,当多个线程同时使用 CAS 更新同一个变量时,只有其中一个线程能够操作成功,而其他线程都会更新失败。不过和同步互斥锁不同的是,更新失败的线程并不会被阻塞,而是被告知这次由于竞争而导致的操作失败,但还可以再次尝试CAS 被广泛应用在并发编程领域中,以实现那些不会被打原创 2020-09-19 11:56:02 · 586 阅读 · 0 评论 -
volatile 的作用是什么?与 synchronized 有什么异同?
volatile 是什么它是 Java 中的一个关键字,是一种同步机制。当某个变量是共享变量,且这个变量是被 volatile 修饰的,那么在修改了这个变量的值之后,再读取该变量的值时,可以保证获取到的是修改后的最新的值,而不是过期的值相比于 synchronized 或者 Lock,volatile 是更轻量的,因为使用 volatile 不会发生上下文切换等开销很大的情况,不会让线程阻塞。但正是由于它的开销相对比较小,所以它的效果,也就是能力,相对也小一些虽然说 volatile 是用来保证原创 2020-09-16 09:40:24 · 199 阅读 · 0 评论 -
Condition、object.wait() 和 notify() 的关系?
Condition接口作用我们假设线程 1 需要等待某些条件满足后,才能继续运行,这个条件会根据业务场景不同,有不同的可能性,比如等待某个时间点到达或者等待某些任务处理完毕。在这种情况下,我们就可以执行 Condition 的 await 方法,一旦执行了该方法,这个线程就会进入 WAITING 状态通常会有另外一个线程,我们把它称作线程 2,它去达成对应的条件,直到这个条件达成之后,那么,线程 2 调用 Condition 的 signal 方法 [或 signalAll 方法],代表“这个条原创 2020-09-16 09:45:02 · 231 阅读 · 0 评论 -
CyclicBarrier 和 CountdownLatch 有什么异同?
CyclicBarrier作用CyclicBarrier 和 CountDownLatch 确实有一定的相似性,它们都能阻塞一个或者一组线程,直到某种预定的条件达到之后,这些之前在等待的线程才会统一出发,继续向下执行。正因为它们有这个相似点,你可能会认为它们的作用是完全一样的,其实并不是CyclicBarrier 可以构造出一个集结点,当某一个线程执行 await() 的时候,它就会到这个集结点开始等待,等待这个栅栏被撤销。直到预定数量的线程都到了这个集结点之后,这个栅栏就会被撤销,之前等待的线程就原创 2020-09-16 09:45:23 · 275 阅读 · 0 评论 -
CountDownLatch 是如何安排线程执行顺序的?
CountDownLatch,它是 JDK 提供的并发流程控制的工具类,它是在 java.util.concurrent 包下,在 JDK1.5 以后加入的比如我们去游乐园坐激流勇进,有的时候游乐园里人不是那么多,这时,管理员会让你稍等一下,等人坐满了再开船,这样的话可以在一定程度上节约游乐园的成本。座位有多少,就需要等多少人,这就是CountDownLatch的核心思想,等到一个设定的数值达到之后,才能出发流程图把激流勇进的例子用流程图的方式来表示最开始 CountDownLatc..原创 2020-09-16 09:45:33 · 899 阅读 · 1 评论 -
信号量能被 FixedThreadPool 替代吗?
Semaphore 信号量从图中可以看出,信号量的一个最主要的作用就是,来控制那些需要限制并发访问量的资源。具体来讲,信号量会维护“许可证”的计数,而线程去访问共享资源前,必须先拿到许可证。线程可以从信号量中去“获取”一个许可证,一旦线程获取之后,信号量持有的许可证就转移过去了,所以信号量手中剩余的许可证要减一同理,线程也可以“释放”一个许可证,如果线程释放了许可证,这个许可证相当于被归还给信号量了,于是信号量中的许可证的可用数量加一。当信号量拥有的许可证数量减到 0 时,如果下个线程还想要获得原创 2020-09-16 09:45:50 · 384 阅读 · 0 评论 -
如何利用 CompletableFuture 实现“旅游平台”问题?
旅游平台问题如果想要搭建一个旅游平台,经常会有这样的需求,那就是用户想同时获取多家航空公司的航班信息。比如,从北京到上海的机票钱是多少?有很多家航空公司都有这样的航班信息,所以应该把所有航空公司的航班、票价等信息都获取到,然后再聚合。由于每个航空公司都有自己的服务器,所以分别去请求它们的服务器就可以了,比如请求国航、海航、东航等,如下图所示串行一种比较原始的方式是用串行的方式来解决这个问题比如我们想获取价格,要先去访问国航,在这里叫作 website 1,然后再去访问海航 websi原创 2020-09-16 09:45:40 · 215 阅读 · 0 评论 -
使用 Future 有哪些注意点?Future 产生新的线程了吗?
Future 的注意点当 for 循环批量获取 Future 的结果时容易 block,get 方法调用时应使用 timeout 限制首先,假设一共有四个任务需要执行,我们都把它放到线程池中,然后它获取的时候是按照从 1 到 4 的顺序,也就是执行 get() 方法来获取的,代码如下所示publicclassFutureDemo{publicstaticvoidmain(String[]args){//创建线程池ExecutorS...原创 2020-09-16 09:46:10 · 639 阅读 · 0 评论 -
Future 的主要功能是什么?
Future 类的作用Future 最主要的作用是,比如当做一定运算的时候,运算过程可能比较耗时,有时会去查数据库,或是繁重的计算,比如压缩、加密等,在这种情况下,如果我们一直在原地等待方法返回,显然是不明智的,整体程序的运行效率会大大降低。我们可以把运算的过程放到子线程去执行,再通过 Future 去控制子线程执行的计算过程,最后获取到计算结果。这样一来就可以把整个程序的运行效率提高,是一种异步的思想Callable 和 Future 的关系Callable 接口相比于 Runnable 的一原创 2020-09-16 09:46:00 · 1701 阅读 · 0 评论 -
Callable 和 Runnable 的不同?
为什么需要 Callable?Runnable 的缺陷 不能返回一个返回值 对于 Runnable 而言,它不能返回一个返回值,虽然可以利用其他的一些办法,比如在 Runnable 方法中写入日志文件或者修改某个共享的对象的办法,来达到保存线程执行结果的目的,但这种解决问题的行为千曲百折,属于曲线救国,效率着实不高实际上,在很多情况下执行一个子线程时,我们都希望能得到执行的任务的结果,也就是说,我们是需要得到返回值的,比如请求网络、查询数据库等。可是 Runnable 不能返回一个返回值,这是原创 2020-09-16 09:41:22 · 324 阅读 · 0 评论 -
为何每次用完 ThreadLocal 都要调用 remove()?——内存泄漏
什么是内存泄漏内存泄漏指的是,当某一个对象不再有用的时候,占用的内存却不能被回收,这就叫作内存泄漏因为通常情况下,如果一个对象不再有用,那么我们的垃圾回收器 GC,就应该把这部分内存给清理掉。这样的话,就可以让这部分内存后续重新分配到其他的地方去使用;否则,如果对象没有用,但一直不能被回收,这样的垃圾对象如果积累的越来越多,则会导致我们可用的内存越来越少,最后发生内存不够用的 OOM 错误Key 的泄漏每一个 Thread 都有一个 ThreadLocal.ThreadLocalMap.原创 2020-09-16 09:40:56 · 8263 阅读 · 6 评论 -
多个 ThreadLocal 在 Thread 中的 threadlocals 里是怎么存储的?
Thread、 ThreadLocal 及 ThreadLocalMap 三者之间的关系看到最左下角的 Thread 1,这是一个线程,它的箭头指向了 ThreadLocalMap 1,其要表达的意思是,每个 Thread 对象中都持有一个 ThreadLocalMap 类型的成员变量,在这里 Thread 1 所拥有的成员变量就是 ThreadLocalMap 1而这个 ThreadLocalMap 自身类似于是一个 Map,里面会有一个个 key value 形式的键值对。那么我们就来看一.原创 2020-09-15 14:40:23 · 2616 阅读 · 0 评论 -
ThreadLocal 是用来解决共享资源的多线程访问的问题吗?
不是,ThreadLocal 并不是用来解决共享资源问题的。虽然 ThreadLocal 确实可以用于解决多线程情况下的线程安全问题,但其资源并不是共享的,而是每个线程独享的ThreadLocal 解决线程安全问题的时候,相比于使用“锁”而言,换了一个思路,把资源变成了各线程独享的资源,非常巧妙地避免了同步操作。具体而言,它可以在 initialValue 中 new 出自己线程独享的资源,而多个线程之间,它们所访问的对象本身是不共享的,自然就不存在任何并发问题。这是 ThreadLocal 解决并发问原创 2020-09-15 14:28:35 · 723 阅读 · 0 评论 -
ThreadLocal 适合用在哪些实际生产的场景中?
在通常的业务开发中,ThreadLocal 有两种典型的使用场景场景1,ThreadLocal 用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全场景2,ThreadLocal 用作每个线程内需要独立保存信息,以便供其他方法更方便地获取该信息的场景。每个线程获取到的信息可能都是不一样的,前面执行的方法保存了信息后,后续方法可以通过 ThreadLocal 直接获取到,避免了传参,类似于全局变量的概念典型场景1原创 2020-09-15 12:22:32 · 479 阅读 · 1 评论 -
Java 8 中 Adder 和 Accumulator 有什么区别?
Adder简介对于 Adder 而言,比如最典型的 LongAdder,在高并发下 LongAdder 比 AtomicLong 效率更高,因为对于 AtomicLong 而言,它只适合用于低并发场景,否则在高并发的场景下,由于 CAS 的冲突概率大,会导致经常自旋,影响整体效率而 LongAdder 引入了分段锁的概念,当竞争不激烈的时候,所有线程都是通过 CAS 对同一个 Base 变量进行修改,但是当竞争激烈的时候,LongAdder 会把不同线程对应到不同的 Cell 上进行修改,降低了冲突原创 2020-09-15 11:39:26 · 239 阅读 · 0 评论 -
AtomicInteger 和 synchronized 的异同点?
代码对比首先,原始的线程不安全的情况的代码如下所示public class Test implements Runnable { static int value = 0; public static void main(String[] args) throws InterruptedException { Runnable runnable = new Test(); Thread thread1 = new Thread(runnable)原创 2020-09-15 11:28:27 · 431 阅读 · 0 评论 -
原子类和 volatile 有什么异同?
首先看一个案例,如图所示,我们有两个线程在图中左上角可以看出,有一个公共的 boolean flag 标记位,最开始赋值为 true,然后线程 2 会进入一个 while 循环,并且根据这个 flag 也就是标记位的值来决定是否继续执行或着退出最开始由于 flag 的值是 true,所以首先会在这里执行一定时期的循环。然后假设在某一时刻,线程 1 把这个 flag 的值改为 false 了,它所希望的是,线程 2 看到这个变化后停止运行但是这样做其实是有风险的,线程 2 可能并不能立刻停下来原创 2020-09-15 11:17:07 · 899 阅读 · 3 评论 -
AtomicInteger 在高并发下性能不好,如何解决?为什么?
JDK1.5 中新增了并发情况下使用的 Integer/Long所对应的原子类 AtomicInteger 和 AtomicLong在并发的场景下,如果我们需要实现计数器,可以利用 AtomicInteger 和 AtomicLong,这样一来,就可以避免加锁和复杂的代码逻辑,有了它们之后,我们只需要执行对应的封装好的方法,例如对这两个变量进行原子的增操作或原子的减操作,就可以满足大部分业务场景的需求AtomicLong存在的问题/***描述:在16个线程下使用AtomicLong*...原创 2020-09-15 10:59:35 · 1273 阅读 · 0 评论 -
原子类是如何利用 CAS 保证线程安全的?
什么是原子类?原子类有什么作用?在编程领域里,原子性意味着“一组操作要么全都操作成功,要么全都失败,不能只操作成功其中的一部分”。而 java.util.concurrent.atomic 下的类,就是具有原子性的类,可以原子性地执行添加、递增、递减等操作。比如多线程下的线程不安全的 i++ 问题,到了原子类这里,就可以用功能相同且线程安全的 getAndIncrement 方法来优雅地解决原子类的作用和锁有类似之处,是为了保证并发情况下线程安全。不过原子类相比于锁,有一定的优势粒度更细:原子原创 2020-09-15 10:41:29 · 899 阅读 · 0 评论 -
如何选择适合自己的阻塞队列?
线程池对于阻塞队列的选择FixedThreadPool(SingleThreadExecutor 同理)选取的是 LinkedBlockingQueue因为 LinkedBlockingQueue 不同于 ArrayBlockingQueue,ArrayBlockingQueue 的容量是有限的,而 LinkedBlockingQueue 是链表长度默认是可以无限延长的由于 FixedThreadPool 的线程数是固定的,在任务激增的时候,它无法增加更多的线程来帮忙处理 Task,所以需要像原创 2020-09-15 10:04:51 · 675 阅读 · 0 评论 -
阻塞队列(ArrayBlockingQueue)和非阻塞队列(ConcurrentLinkedQueue)的并发安全原理是什么?
ArrayBlockingQueue 源码分析ArrayBlockingQueue 有以下几个重要的属性//用于存放元素的数组finalObject[]items;//下一次读取操作的位置inttakeIndex;//下一次写入操作的位置intputIndex;//队列中的元素数量intcount;第一个就是最核心的、用于存储元素的 Object 类型的数组;然后它还会有两个位置变量,分别是 takeIndex 和 putIndex,这两个变量就是用来标明下一...原创 2020-09-15 09:46:04 · 466 阅读 · 0 评论 -
有哪几种常见的阻塞队列?
BlockingQueue 接口的实现类都被放在了 J.U.C 包中,本课时将对常见的和常用的实现类进行介绍,包括 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue,以及 DelayQueueArrayBlockingQueueArrayBlockingQueue 是最典型的有界队列,其内部是用数组存储元素的,利用 ReentrantLock 实现线程安全在创建它的时候就需要指定它的容.原创 2020-09-14 16:48:35 · 999 阅读 · 0 评论 -
阻塞队列包含哪些常用的方法?
把 BlockingQueue 中最常用的和添加、删除相关的 8 个方法列出来,并且把它们分为三组,每组方法都和添加、移除元素相关这三组方法由于功能很类似,所以比较容易混淆。它们的区别仅在于特殊情况:当队列满了无法添加元素,或者是队列空了无法移除元素时,不同组的方法对于这种特殊情况会有不同的处理方式抛出异常:add、remove、element 返回结果但不抛出异常:offer、poll、peek 阻塞:put、take第一组:add、remove、elementadd 方法add原创 2020-09-14 16:29:37 · 463 阅读 · 0 评论 -
什么是阻塞队列?
阻塞队列的作用阻塞队列,也就是 BlockingQueue,它是一个接口,如代码所示publicinterfaceBlockingQueue<E>extendsQueue<E>{...}BlockingQueue 继承了 Queue 接口,是队列的一种。Queue 和 BlockingQueue 都是在 Java 5 中加入的BlockingQueue 是线程安全的,我们在很多场景下都可以利用线程安全的队列来优雅地解决我们业务自身的线程安全问题。比如说,使...原创 2020-09-14 16:09:32 · 750 阅读 · 0 评论 -
CopyOnWriteArrayList 有什么特点?
在 CopyOnWriteArrayList 出现之前,我们已经有了 ArrayList 和 LinkedList 作为 List 的数组和链表的实现,而且也有了线程安全的 Vector 和 Collections.synchronizedList() 可以使用。首先就让我们来看下线程安全的 Vector 的 size 和 get 方法的代码publicsynchronizedintsize(){returnelementCount;}publicsynchronizedE...原创 2020-09-14 15:45:18 · 332 阅读 · 0 评论 -
同样是线程安全,ConcurrentHashMap 和 Hashtable 的区别?
出现的版本不同Hashtable 在 JDK1.0 的时候就存在了,并在 JDK1.2 版本中实现了 Map 接口,成为了集合框架的一员。而 ConcurrentHashMap 则是在 JDK1.5 中才出现的,也正是因为它们出现的年代不同,而后出现的往往是对前面出现的类的优化,所以它们在实现方式以及性能上,也存在着较大的不同实现线程安全的方式不同虽然 ConcurrentHashMap 和 Hashtable 它们两个都是线程安全的,但是从原理上分析,Hashtable 实现并发安全的原理是通原创 2020-09-14 15:11:02 · 400 阅读 · 0 评论 -
为什么 Map 桶中超过 8 个才转为红黑树?
JDK1.8 的 HashMap 和 ConcurrentHashMap 都有这样一个特点:最开始的 Map 是空的,因为里面没有任何元素,往里放元素时会计算 hash 值,计算之后,第 1 个 value 会首先占用一个桶(也称为槽点)位置,后续如果经过计算发现需要落到同一个桶中,那么便会使用链表的形式往后延长,俗称“拉链法”,如图所示图中,有的桶是空的, 比如第 4 个;有的只有一个元素,比如 1、3、6;有的就是刚才说的拉链法,比如第 2 和第 5 个桶当链表长度大于或等于阈值(默认为.原创 2020-09-14 14:54:55 · 744 阅读 · 0 评论