![](https://img-blog.csdnimg.cn/20190927151026427.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
大白话-人人都看的懂得java并发编程
文章平均质量分 91
人人都能看懂的线程详解
IT社团
这个作者很懒,什么都没留下…
展开
-
56、volatile 的作用和适用场景,以及它与 synchronized 有什么异同
本课时我们主要介绍 volatile 的作用和适用场景,以及它与 synchronized 有什么异同。原创 2024-06-06 20:44:25 · 1342 阅读 · 0 评论 -
55、什么是 happens-before 关系
Happens-before 关系是用来描述和可见性相关问题的:如果第一个操作 happens-before 第二个操作(也可以描述为,第一个操作和第二个操作之间满足 happens-before 关系),那么我们就说第一个操作对于第二个操作一定是可见的,也就是第二个操作在执行时就一定能保证看见第一个操作执行的结果。以上就是我们对于 happens-before 关系的介绍。本课时首先介绍了什么是 happens-before 关系,然后举了一个不具备 happens-before 关系的例子;原创 2024-06-06 20:40:56 · 1018 阅读 · 0 评论 -
54、java中主内存和工作内存的关系是什么?
Java 作为高级语言,屏蔽了 L1 缓存、L2 缓存、L3 缓存,也就是多层缓存的这些底层细节,用 JMM 定义了一套读写数据的规范。我们不再需要关心 L1 缓存、L2 缓存、L3 缓存等多层缓存的问题,我们只需要关心 JMM 抽象出来的主内存和工作内存的概念。每个线程只能够直接接触到工作内存,无法直接操作主内存,而工作内存中所保存的正是主内存的共享变量的副本,主内存和工作内存之间的通信是由 JMM 控制的。原创 2024-06-06 20:37:44 · 709 阅读 · 0 评论 -
53、什么是“可见性”问题?
本课时我们主要讲解什么是“可见性”问题?原创 2024-06-06 20:33:12 · 945 阅读 · 0 评论 -
52、 Java 中的原子性和原子操作
在编程中,具备原子性的操作被称为原子操作。原子操作是指一系列的操作,要么全部发生,要么全部不发生,不会出现执行一半就终止的情况。比如转账行为就是一个原子操作,该过程包含扣除余额、银行系统生成转账记录、对方余额增加等一系列操作。虽然整个过程包含多个操作,但由于这一系列操作被合并成一个原子操作,所以它们要么全部执行成功,要么全部不执行,不会出现执行一半的情况。比如我的余额已经扣除,但是对方的余额却不增加,这种情况是不会出现的,所以说转账行为是具备原子性的。而具有原子性的原子操作,天然具备线程安全的特性。原创 2024-06-06 20:23:56 · 799 阅读 · 0 评论 -
51、java中什么是指令重排序?为什么要重排序?
假设我们写了一个 Java 程序,包含一系列的语句,我们会默认期望这些语句的实际运行顺序和写的代码顺序一致。但实际上,编译器、JVM 或者 CPU 都有可能出于优化等目的,对于实际指令执行的顺序进行调整,这就是重排序。重排序的好处:提高处理速度你可能感到很困惑,为什么要重排序?这样做有什么好处呢?我们来举一个具体的例子。图中左侧是 3 行 Java 代码,右侧是这 3 行代码可能被转化成的指令。原创 2024-06-05 21:04:29 · 329 阅读 · 0 评论 -
50、什么是 Java 内存模型?
以上就是本课时的内容了。本课时,我们先对 JVM 内存结构和 Java 内存模型这两个容易混淆的概念进行了辨析,然后从宏观层面讲解了什么是 Java 内存模型,接下来,我们的脚步从 Java 代码逐渐往下探索,解释了为什么需要 JMM 以及什么是 JMM。原创 2024-06-05 21:01:14 · 447 阅读 · 0 评论 -
49、ThreadLocal为什么会造成内存泄露?
内存泄漏指的是,当某一个对象不再有用的时候,占用的内存却不能被回收,这就叫作内存泄漏。因为通常情况下,如果一个对象不再有用,那么我们的垃圾回收器 GC,就应该把这部分内存给清理掉。这样的话,就可以让这部分内存后续重新分配到其他的地方去使用;否则,如果对象没有用,但一直不能被回收,这样的垃圾对象如果积累的越来越多,则会导致我们可用的内存越来越少,最后发生内存不够用的 OOM 错误。下面我们来分析一下,在 ThreadLocal 中这样的内存泄漏是如何发生的。原创 2024-05-07 09:52:06 · 921 阅读 · 0 评论 -
48、ThreadLocal内部原理是什么?
本课时我们主要分析一下在 Thread 中多个 ThreadLocal 是怎么存储的。原创 2024-05-06 20:14:06 · 950 阅读 · 0 评论 -
47、ThreadLocal 是不是用来解决共享资源的多线程访问的?
在本课时中,首先介绍了 ThreadLocal 是不是用来解决共享资源的多线程访问的问题的,答案是“不是”,因为对于 ThreadLocal 而言,每个线程中的资源并不共享;然后我们又介绍了 ThreadLocal 和 synchronized 的关系。原创 2024-05-06 19:01:54 · 508 阅读 · 0 评论 -
45、如何选择适合自己的阻塞队列?
本课时我们主要讲解如何选择适合自己的阻塞队列。他山之石,可以攻玉。对于如何选择最合适的阻塞队列这个问题,实际上线程池已经率先给我们做了表率。线程池有很多种,不同种类的线程池会根据自己的特点,来选择适合自己的阻塞队列。所以我们就首先来复习一下这些非常经典的线程池是如何挑选阻塞队列的,借鉴它们的经验之后,我们再去总结一套规则,来归纳出自己在选取阻塞队列时可以对哪些点进行考虑。原创 2024-04-29 20:21:40 · 681 阅读 · 0 评论 -
44、阻塞和非阻塞队列的并发安全原理是什么?
最后我们来做一下总结。本课时我们分析了阻塞队列和非阻塞队列的并发安全原理,其中阻塞队列最主要是利用了 ReentrantLock 以及它的 Condition 来实现,而非阻塞队列则是利用 CAS 方法实现线程安全。原创 2024-04-29 20:16:03 · 722 阅读 · 0 评论 -
43、有哪几种常见的阻塞队列?
以上就是本课时的内容,我们对于 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue 以及 DelayQueue 这些常见的和常用的阻塞队列的特点进行了讲解。原创 2024-04-29 20:08:59 · 561 阅读 · 0 评论 -
41、什么是阻塞队列?
在本课时中我们主要讲解一下什么是阻塞队列。原创 2024-04-29 19:59:07 · 559 阅读 · 0 评论 -
62、AtomicInteger 在高并发下性能不好,如何解决?
在并发不高的时候,两个类都差不多。竞争激烈的时候,LongAdder 会通过计算出每个线程的 hash 值来给线程分配到不同的 Cell 上去,每个 Cell 相当于是一个独立的计数器,这样一来就不会和其他的计数器干扰,Cell 之间并不存在竞争关系,所以在自加的过程中,就大大减少了刚才的 flush 和 refresh,以及降低了冲突的概率,这就是为什么 LongAdder 的吞吐量比 AtomicLong 大的原因,本质是空间换时间,因为它有多个计数器同时在工作,所以占用的内存也要相对更大一些。原创 2024-04-14 21:34:13 · 812 阅读 · 0 评论 -
61、原子类是如何利用 CAS 保证线程安全的?
这段代码就演示了这个类的用法,比如说我们有两个类,它们都是 Score 类型的,Score 类型内部会有一个分数,也叫作 core,那么这两个分数的实例分别叫作数学 math 和计算机 computer,然后我们还声明了一个 AtomicIntegerFieldUpdater,在它构造的时候传入了两个参数,第一个是 Score.class,这是我们的类名,第二个是属性名,叫作 score。这个参数就是我想让当前这个原子类改变多少值,可以是正数也可以是负数,如果是正数就是增加,如果是负数就是减少。原创 2024-04-14 21:33:43 · 450 阅读 · 0 评论 -
40、 CopyOnWriteArrayList 有什么特点?
以上我们对 CopyOnWriteArrayList 进行了介绍。我们分别介绍了在它诞生之前的 Vector 和 Collections.synchronizedList() 的特点,CopyOnWriteArrayList 的适用场景、读写规则,还介绍了它的两个特点,分别是写时复制和迭代期间允许修改集合内容。我们还介绍了它的三个缺点,分别是内存占用问题,在元素较多或者复杂的情况下复制的开销大问题,以及数据一致性问题。最后我们对于它的重要源码进行了解析。原创 2024-04-14 13:20:07 · 905 阅读 · 0 评论 -
39、同样是线程安全,ConcurrentHashMap 与 Hashtable 到底有什么区别呢?
本课时总结了 ConcurrentHashMap 与 Hashtable 的区别,虽然它们都是线程安全的,但是在出现的版本上、实现线程安全的方式上、性能上,以及迭代时是否支持修改等方面都有较大的不同,如果我们有并发的场景,那么使用 ConcurrentHashMap 是最合适的,相反,Hashtable 已经不再推荐使用。原创 2024-04-14 13:14:39 · 824 阅读 · 0 评论 -
38、为什么 Map 的桶中超过 8 个才转为红黑树?
事实上,链表长度超过 8 就转为红黑树的设计,更多的是为了防止用户自己实现了不好的哈希算法时导致链表过长,从而导致查询效率低,而此时转为红黑树更多的是一种保底策略,用来保证极端情况下查询的效率。通常如果 hash 算法正常的话,那么链表的长度也不会很长,那么红黑树也不会带来明显的查询时间上的优势,反而会增加空间负担。所以通常情况下,并没有必要转为红黑树,所以就选择了概率非常小,小于千万分之一概率,也就是长度为 8 的概率,把长度 8 作为转化的默认阈值。原创 2024-04-14 13:12:41 · 958 阅读 · 0 评论 -
37、ConcurrentHahMap 在 Java7 和 8 有何不同?
众所周知,ConcurrentHahMap是线程安全的map。但在 Java 8 中,对于 ConcurrentHashMap 这个常用的工具类进行了很大的升级,对比之前 Java 7 版本在诸多方面都进行了调整和变化。不过,在 Java 7 中的 Segment 的设计思想依然具有参考和学习的价值,所以在很多情况下,面试官都会问你:ConcurrentHashMap 在 Java 7 和 Java 8 中的结构分别是什么?它们有什么相同点和不同点?原创 2024-04-14 11:13:04 · 868 阅读 · 0 评论 -
36、HashMap 为什么是线程不安全的?
所以综上所述,HashMap 是线程不安全的,在多线程使用场景中如果需要使用 Map,应该尽量避免使用线程不安全的 HashMap。同时,虽然 Collections.synchronizedMap(new HashMap()) 是线程安全的,但是效率低下,因为内部用了很多的 synchronized,多个线程不能同时操作。推荐使用线程安全同时性能比较好的 ConcurrentHashMap。关于 ConcurrentHashMap 我们会在下一个课时中介绍。原创 2024-04-14 10:59:56 · 777 阅读 · 0 评论 -
35、 JVM 对synchronized锁进行了哪些优化呢?
本课时我们主要讲解 JVM 对锁进行了哪些优化呢?相比于 JDK 1.5,在 JDK 1.6 中 HotSopt 虚拟机对 synchronized 内置锁的性能进行了很多优化,。有了这些优化措施后,synchronized 锁的性能得到了大幅提高,下面我们分别介绍这些具体的优化。原创 2024-04-13 14:02:14 · 607 阅读 · 0 评论 -
34、什么是自旋锁?以及使用自旋锁的好处和后果分别是什么呢?
首先,我们了解什么叫自旋?“自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞。原创 2024-04-13 13:57:45 · 973 阅读 · 0 评论 -
33、java读锁应该插队吗?以及什么是读写锁的升降级
对于 ReentrantReadWriteLock 而言。插队策略公平策略下,只要队列里有线程已经在排队,就不允许插队。非公平策略下:如果允许读锁插队,那么由于读锁可以同时被多个线程持有,所以可能造成源源不断的后面的线程一直插队成功,导致读锁一直不能完全释放,从而导致写锁一直等待,为了防止“饥饿”,在等待队列的头结点是尝试获取写锁的线程的时候,不允许读锁插队。原创 2024-04-13 13:52:39 · 946 阅读 · 0 评论 -
31、java公平锁和非公平锁,以及为什么要“非公平”?
公平锁指的是按照线程请求的顺序,来分配锁;而非公平锁指的是不完全按照请求的顺序,在一定情况下,可以允许插队。但需要注意这里的非公平并不是指完全的随机,不是说线程可以任意插队,而是仅仅“在合适的时机”插队。那么什么时候是合适的时机呢?假设当前线程在请求获取锁的时候,恰巧前一个持有锁的线程释放了这把锁,那么当前申请锁的线程就可以不顾已经等待的线程而选择立刻插队。但是如果当前线程请求的时候,前一个线程并没有在那一时刻释放锁,那么当前线程还是一样会进入等待队列。原创 2024-04-13 13:42:15 · 854 阅读 · 0 评论 -
27-1、java有哪几种锁?
本课时我们首先会对锁的分类有一个整体的概念,了解锁究竟有哪些分类标准。然后在后续的课程中,会对其中重要的锁进行详细讲解。原创 2024-04-13 13:29:58 · 786 阅读 · 0 评论 -
30、synchronized 和 Lock 的异同点,以及该如何选择?
本课时我们主要学习 synchronized 和 Lock 的异同点,以及该如何选择。原创 2024-04-13 13:28:22 · 895 阅读 · 0 评论 -
29、java的Lock 有哪几种常用的方法,以及它们分别都是干什么用的?
Lock 接口是 Java 5 引入的,最常见的实现类是 ReentrantLock,可以起到“锁”的作用。Lock 和 synchronized 是两种最常见的锁,锁是一种工具,用于控制对共享资源的访问。而 Lock 和 synchronized 都可以达到线程安全的目的,但是在使用上和功能上又有较大的不同。所以 Lock 并不是用来代替 synchronized 的,而是当使用 synchronized 不合适或不足以满足要求的时候,Lock 可以用来提供更高级功能的。原创 2024-04-13 13:28:03 · 733 阅读 · 0 评论 -
28、synchronized背后的monitor 锁原理?
好了,本课时的内容就全部讲完了,本课时我们讲解了获取和释放 monitor 的时机,以及被 synchronized 修饰的等价代码,然后我们还利用 javac 和 javap 命令查看了 synchronized 代码块以及 synchronized 方法所对应的的反汇编指令,其中同步代码块是利用 monitorenter 和 monitorexit 指令实现的,而同步方法则是利用 flags 实现的。原创 2024-04-13 13:27:42 · 623 阅读 · 0 评论 -
27-2、悲观锁和乐观锁本质是什么呢?
本课时我们会讲讲悲观锁和乐观锁。首先我们看下悲观锁与乐观锁是如何进行分类的,悲观锁和乐观锁是从是否锁住资源的角度进行分类的。原创 2024-04-13 13:27:13 · 552 阅读 · 0 评论 -
26、Semaphore 信号量详解
从图中可以看出,信号量的一个最主要的作用就是,来控制那些需要限制并发访问量的资源。具体来讲,信号量会维护“许可证”的计数,而线程去访问共享资源前,必须先拿到许可证。线程可以从信号量中去“获取”一个许可证,一旦线程获取之后,信号量持有的许可证就转移过去了,所以信号量手中剩余的许可证要减一。同理,线程也可以“释放”一个许可证,如果线程释放了许可证,这个许可证相当于被归还给信号量了,于是信号量中的许可证的可用数量加一。原创 2024-04-13 13:26:39 · 713 阅读 · 0 评论 -
25、CyclicBarrier主要作用是什么?和CountDownLatch有什么不同?
以上就是本课时的内容,在本课时中,首先介绍了 CyclicBarrier 的作用、代码示例和执行动作,然后对 CyclicBarrier 和 CountDownLatch 的异同进行了总结。原创 2024-04-12 20:17:51 · 768 阅读 · 0 评论 -
23、如何利用CompletableFuture解决并行查询问题?
最后做一下总结。在本课时中,我们先给出了一个旅游平台问题,它需要获取各航空公司的机票信息,随后进行了代码演进,从串行到并行,再到有超时的并行,最后到不仅有超时的并行,而且如果大家速度都很快,那么也不需要一直等到超时时间到,我们进行了这样的一步一步的迭代。当然除了这几种实现方案之外,还会有其他的实现方案,你能想到哪些实现方案呢?原创 2024-04-12 20:03:38 · 973 阅读 · 0 评论 -
22、java的Future使用有哪些注意点,以及 Future 产生新的线程了吗?
在本课时我们将讲解使用 Future 有哪些注意点,以及 Future 产生新的线程了吗?原创 2024-04-12 19:48:50 · 654 阅读 · 0 评论 -
21、Future 的主要功能是什么?
最后对本课时进行一下总结,在本课时中,我们首先在宏观上讲解了 Future 的作用,然后讲解了 Callable 和 Future 的关系,接着对于 Future 的各个方法进行了详细介绍,最后还给出了 FutureTask 这种方法来创建 Future 的用法。原创 2024-04-12 19:56:57 · 812 阅读 · 0 评论 -
20、为什么需要 Callable?与Runnable 的区别是什么?
在本课时我们将讲解 Callable 和 Runnable 的不同。原创 2024-04-12 17:14:39 · 507 阅读 · 0 评论 -
19、java哪些场景需要额外注意线程安全问题?
线程安全可能会出现场景,①共享变量或者共享资源。②依赖时序的操作。③不同数据之间存在绑定关系。④没有声明自己是线程安全的工具类。共享资源变量:需要保证可见性和原子性。对共享资源的操作要多线成之间可见,修改操作必须是原子操作;依赖时序:则需要保证有序性;绑定关系:应该属性原子性问题,将存在绑定关系的变量的修改操作变为原子操作,可以通过 synchronized 或者加锁的方式来实现;原创 2024-04-12 17:11:26 · 800 阅读 · 0 评论 -
18、多线程为什么有安全问题?
要想弄清楚有哪 3 类线程安全问题,首先需要了解什么是线程安全,线程安全经常在工作中被提到,比如:你的对象不是线程安全的,你的线程发生了安全错误,虽然线程安全经常被提到,但我们可能对线程安全并没有一个明确的定义。《Java Concurrency In Practice》的作者 Brian Goetz 对线程安全是这样理解的,当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行问题,也不需要进行额外的同步,而调用这个对象的行为都可以获得正确的结果,那这个对象便是线程安全的。原创 2024-04-12 17:07:52 · 593 阅读 · 0 评论 -
17、java为什么使用线程会带来性能问题?
在上一课时我们已经学习了多线程带来的线程安全问题,但对于多线程而言,它不仅可能会带来线程安全问题,还有可能会带来性能问题,也许你会奇怪,我们使用多线程的最大目的不就是为了提高性能吗?让多个线程同时工作,加快程序运行速度,为什么反而会带来性能问题呢?这是因为单线程程序是独立工作的,不需要与其他线程进行交互,但多线程之间则需要调度以及合作,调度与合作就会带来性能开销从而产生性能问题。首先,我们来了解究竟什么是性能问题?其实性能问题有许多的表现形式,比如服务器的响应慢、吞吐量低、内存占用过多就属于性能问题。原创 2024-04-12 17:03:15 · 525 阅读 · 0 评论 -
16、为什么使用线程池比每次创建线程要好?
在本课时我们主要学习为什么使用线程池比手动创建线程要好,并讲解具体好在哪里?原创 2024-04-12 16:53:39 · 852 阅读 · 0 评论