自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(191)
  • 收藏
  • 关注

原创 1、什么是设计模式?软件设计的7大原则是什么?

也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。遵循类之间的迪米特法则会是一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接的关联。迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。

2024-04-15 23:21:20 378

原创 62、AtomicInteger 在高并发下性能不好,如何解决?

在并发不高的时候,两个类都差不多。竞争激烈的时候,LongAdder 会通过计算出每个线程的 hash 值来给线程分配到不同的 Cell 上去,每个 Cell 相当于是一个独立的计数器,这样一来就不会和其他的计数器干扰,Cell 之间并不存在竞争关系,所以在自加的过程中,就大大减少了刚才的 flush 和 refresh,以及降低了冲突的概率,这就是为什么 LongAdder 的吞吐量比 AtomicLong 大的原因,本质是空间换时间,因为它有多个计数器同时在工作,所以占用的内存也要相对更大一些。

2024-04-14 21:34:13 692

原创 61、原子类是如何利用 CAS 保证线程安全的?

这段代码就演示了这个类的用法,比如说我们有两个类,它们都是 Score 类型的,Score 类型内部会有一个分数,也叫作 core,那么这两个分数的实例分别叫作数学 math 和计算机 computer,然后我们还声明了一个 AtomicIntegerFieldUpdater,在它构造的时候传入了两个参数,第一个是 Score.class,这是我们的类名,第二个是属性名,叫作 score。这个参数就是我想让当前这个原子类改变多少值,可以是正数也可以是负数,如果是正数就是增加,如果是负数就是减少。

2024-04-14 21:33:43 367

原创 40、 CopyOnWriteArrayList 有什么特点?

以上我们对 CopyOnWriteArrayList 进行了介绍。我们分别介绍了在它诞生之前的 Vector 和 Collections.synchronizedList() 的特点,CopyOnWriteArrayList 的适用场景、读写规则,还介绍了它的两个特点,分别是写时复制和迭代期间允许修改集合内容。我们还介绍了它的三个缺点,分别是内存占用问题,在元素较多或者复杂的情况下复制的开销大问题,以及数据一致性问题。最后我们对于它的重要源码进行了解析。

2024-04-14 13:20:07 756

原创 39、同样是线程安全,ConcurrentHashMap 与 Hashtable 到底有什么区别呢?

本课时总结了 ConcurrentHashMap 与 Hashtable 的区别,虽然它们都是线程安全的,但是在出现的版本上、实现线程安全的方式上、性能上,以及迭代时是否支持修改等方面都有较大的不同,如果我们有并发的场景,那么使用 ConcurrentHashMap 是最合适的,相反,Hashtable 已经不再推荐使用。

2024-04-14 13:14:39 577

原创 38、为什么 Map 的桶中超过 8 个才转为红黑树?

事实上,链表长度超过 8 就转为红黑树的设计,更多的是为了防止用户自己实现了不好的哈希算法时导致链表过长,从而导致查询效率低,而此时转为红黑树更多的是一种保底策略,用来保证极端情况下查询的效率。通常如果 hash 算法正常的话,那么链表的长度也不会很长,那么红黑树也不会带来明显的查询时间上的优势,反而会增加空间负担。所以通常情况下,并没有必要转为红黑树,所以就选择了概率非常小,小于千万分之一概率,也就是长度为 8 的概率,把长度 8 作为转化的默认阈值。

2024-04-14 13:12:41 927

原创 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 656

原创 36、HashMap 为什么是线程不安全的?

所以综上所述,HashMap 是线程不安全的,在多线程使用场景中如果需要使用 Map,应该尽量避免使用线程不安全的 HashMap。同时,虽然 Collections.synchronizedMap(new HashMap()) 是线程安全的,但是效率低下,因为内部用了很多的 synchronized,多个线程不能同时操作。推荐使用线程安全同时性能比较好的 ConcurrentHashMap。关于 ConcurrentHashMap 我们会在下一个课时中介绍。

2024-04-14 10:59:56 759

原创 35、 JVM 对synchronized锁进行了哪些优化呢?

本课时我们主要讲解 JVM 对锁进行了哪些优化呢?相比于 JDK 1.5,在 JDK 1.6 中 HotSopt 虚拟机对 synchronized 内置锁的性能进行了很多优化,。有了这些优化措施后,synchronized 锁的性能得到了大幅提高,下面我们分别介绍这些具体的优化。

2024-04-13 14:02:14 591

原创 34、什么是自旋锁?以及使用自旋锁的好处和后果分别是什么呢?

首先,我们了解什么叫自旋?“自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞。

2024-04-13 13:57:45 924

原创 33、java读锁应该插队吗?以及什么是读写锁的升降级

对于 ReentrantReadWriteLock 而言。插队策略公平策略下,只要队列里有线程已经在排队,就不允许插队。非公平策略下:如果允许读锁插队,那么由于读锁可以同时被多个线程持有,所以可能造成源源不断的后面的线程一直插队成功,导致读锁一直不能完全释放,从而导致写锁一直等待,为了防止“饥饿”,在等待队列的头结点是尝试获取写锁的线程的时候,不允许读锁插队。

2024-04-13 13:52:39 935

原创 32、什么事读写锁 ReadWriteLock? 获取锁有哪些规则?

在本课时我们主要讲解读写锁 ReadWriteLock 获取锁有哪些规则呢?在没有读写锁之前,我们假设使用普通的 ReentrantLock,那么虽然我们保证了线程安全,但是也浪费了一定的资源,因为如果多个读操作同时进行,其实并没有线程安全问题,我们可以允许让多个读操作并行,以便提高程序效率。但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题。我们的读写锁就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全。整体

2024-04-13 13:46:28 336

原创 31、java公平锁和非公平锁,以及为什么要“非公平”?

公平锁指的是按照线程请求的顺序,来分配锁;而非公平锁指的是不完全按照请求的顺序,在一定情况下,可以允许插队。但需要注意这里的非公平并不是指完全的随机,不是说线程可以任意插队,而是仅仅“在合适的时机”插队。那么什么时候是合适的时机呢?假设当前线程在请求获取锁的时候,恰巧前一个持有锁的线程释放了这把锁,那么当前申请锁的线程就可以不顾已经等待的线程而选择立刻插队。但是如果当前线程请求的时候,前一个线程并没有在那一时刻释放锁,那么当前线程还是一样会进入等待队列。

2024-04-13 13:42:15 532

原创 27-1、java有哪几种锁?

本课时我们首先会对锁的分类有一个整体的概念,了解锁究竟有哪些分类标准。然后在后续的课程中,会对其中重要的锁进行详细讲解。

2024-04-13 13:29:58 772

原创 30、synchronized 和 Lock 的异同点,以及该如何选择?

本课时我们主要学习 synchronized 和 Lock 的异同点,以及该如何选择。

2024-04-13 13:28:22 881

原创 29、java的Lock 有哪几种常用的方法,以及它们分别都是干什么用的?

Lock 接口是 Java 5 引入的,最常见的实现类是 ReentrantLock,可以起到“锁”的作用。Lock 和 synchronized 是两种最常见的锁,锁是一种工具,用于控制对共享资源的访问。而 Lock 和 synchronized 都可以达到线程安全的目的,但是在使用上和功能上又有较大的不同。所以 Lock 并不是用来代替 synchronized 的,而是当使用 synchronized 不合适或不足以满足要求的时候,Lock 可以用来提供更高级功能的。

2024-04-13 13:28:03 696

原创 28、synchronized背后的monitor 锁原理?

好了,本课时的内容就全部讲完了,本课时我们讲解了获取和释放 monitor 的时机,以及被 synchronized 修饰的等价代码,然后我们还利用 javac 和 javap 命令查看了 synchronized 代码块以及 synchronized 方法所对应的的反汇编指令,其中同步代码块是利用 monitorenter 和 monitorexit 指令实现的,而同步方法则是利用 flags 实现的。

2024-04-13 13:27:42 590

原创 27-2、悲观锁和乐观锁本质是什么呢?

本课时我们会讲讲悲观锁和乐观锁。首先我们看下悲观锁与乐观锁是如何进行分类的,悲观锁和乐观锁是从是否锁住资源的角度进行分类的。

2024-04-13 13:27:13 543

原创 26、Semaphore 信号量详解

从图中可以看出,信号量的一个最主要的作用就是,来控制那些需要限制并发访问量的资源。具体来讲,信号量会维护“许可证”的计数,而线程去访问共享资源前,必须先拿到许可证。线程可以从信号量中去“获取”一个许可证,一旦线程获取之后,信号量持有的许可证就转移过去了,所以信号量手中剩余的许可证要减一。同理,线程也可以“释放”一个许可证,如果线程释放了许可证,这个许可证相当于被归还给信号量了,于是信号量中的许可证的可用数量加一。

2024-04-13 13:26:39 685

原创 25、CyclicBarrier主要作用是什么?和CountDownLatch有什么不同?

以上就是本课时的内容,在本课时中,首先介绍了 CyclicBarrier 的作用、代码示例和执行动作,然后对 CyclicBarrier 和 CountDownLatch 的异同进行了总结。

2024-04-12 20:17:51 759

原创 24、CountDownLatch主要作用是什么?

CountDownLatch 类在创建实例的时候,需要在构造函数中传入倒数次数,然后由需要等待的线程去调用 await 方法开始等待,而每一次其他线程调用了 countDown 方法之后,计数便会减 1,直到减为 0 时,之前等待的线程便会继续运行。

2024-04-12 20:11:01 781

原创 23、如何利用CompletableFuture解决并行查询问题?

最后做一下总结。在本课时中,我们先给出了一个旅游平台问题,它需要获取各航空公司的机票信息,随后进行了代码演进,从串行到并行,再到有超时的并行,最后到不仅有超时的并行,而且如果大家速度都很快,那么也不需要一直等到超时时间到,我们进行了这样的一步一步的迭代。当然除了这几种实现方案之外,还会有其他的实现方案,你能想到哪些实现方案呢?

2024-04-12 20:03:38 924

原创 21、Future 的主要功能是什么?

最后对本课时进行一下总结,在本课时中,我们首先在宏观上讲解了 Future 的作用,然后讲解了 Callable 和 Future 的关系,接着对于 Future 的各个方法进行了详细介绍,最后还给出了 FutureTask 这种方法来创建 Future 的用法。

2024-04-12 19:56:57 751

原创 22、java的Future使用有哪些注意点,以及 Future 产生新的线程了吗?

在本课时我们将讲解使用 Future 有哪些注意点,以及 Future 产生新的线程了吗?

2024-04-12 19:48:50 624

原创 20、为什么需要 Callable?与Runnable 的区别是什么?

在本课时我们将讲解 Callable 和 Runnable 的不同。

2024-04-12 17:14:39 494

原创 19、java哪些场景需要额外注意线程安全问题?

线程安全可能会出现场景,①共享变量或者共享资源。②依赖时序的操作。③不同数据之间存在绑定关系。④没有声明自己是线程安全的工具类。共享资源变量:需要保证可见性和原子性。对共享资源的操作要多线成之间可见,修改操作必须是原子操作;依赖时序:则需要保证有序性;绑定关系:应该属性原子性问题,将存在绑定关系的变量的修改操作变为原子操作,可以通过 synchronized 或者加锁的方式来实现;

2024-04-12 17:11:26 770

原创 18、多线程为什么有安全问题?

要想弄清楚有哪 3 类线程安全问题,首先需要了解什么是线程安全,线程安全经常在工作中被提到,比如:你的对象不是线程安全的,你的线程发生了安全错误,虽然线程安全经常被提到,但我们可能对线程安全并没有一个明确的定义。《Java Concurrency In Practice》的作者 Brian Goetz 对线程安全是这样理解的,当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行问题,也不需要进行额外的同步,而调用这个对象的行为都可以获得正确的结果,那这个对象便是线程安全的。

2024-04-12 17:07:52 584

原创 17、java为什么使用线程会带来性能问题?

在上一课时我们已经学习了多线程带来的线程安全问题,但对于多线程而言,它不仅可能会带来线程安全问题,还有可能会带来性能问题,也许你会奇怪,我们使用多线程的最大目的不就是为了提高性能吗?让多个线程同时工作,加快程序运行速度,为什么反而会带来性能问题呢?这是因为单线程程序是独立工作的,不需要与其他线程进行交互,但多线程之间则需要调度以及合作,调度与合作就会带来性能开销从而产生性能问题。首先,我们来了解究竟什么是性能问题?其实性能问题有许多的表现形式,比如服务器的响应慢、吞吐量低、内存占用过多就属于性能问题。

2024-04-12 17:03:15 507

原创 16、为什么使用线程池比每次创建线程要好?

在本课时我们主要学习为什么使用线程池比手动创建线程要好,并讲解具体好在哪里?

2024-04-12 16:53:39 831

原创 15、java线程池中的线程复用的原理是什么?

在本课时我们主要学习线程复用的原理,以及对线程池的 execute 这个非常重要的方法进行源码解析。

2024-04-12 16:40:25 967

原创 14、java如何正确关闭线程池?

在掌握了这 5 种关闭线程池相关的方法之后,我们就可以根据自己的业务需要,选择合适的方法来停止线程池,比如通常我们可以用 shutdown() 方法来关闭,这样可以让已提交的任务都执行完毕,但是如果情况紧急,那我们就可以用 shutdownNow 方法来加快线程池“终结”的速度。正常停止线程的本质,是让线程任务的run方法执行完,对应到线程池的线程,就是Worker类的run方法执行完。这个run方法执行完的前提是getTask()返回的是null。

2024-04-12 15:00:04 721

原创 13、java如何根据自己的实际需求来定制自己的线程池?

所以定制自己的线程池和我们的业务是强相关的,首先我们需要掌握每个参数的含义,以及常见的选项,然后根据实际需要,比如说并发量、内存大小、是否接受任务被拒绝等一系列因素去定制一个非常适合自己业务的线程池,这样既不会导致内存不足,同时又可以用合适数量的线程来保障任务执行的效率,并在拒绝任务时有所记录方便日后进行追溯。

2024-04-12 14:55:30 502

原创 12、java合适的线程数量是多少?

在本课时我们主要学习合适的线程数量是多少,以及 CPU 核心数和线程数的关系。你可能经常在面试中被问到这两个问题,如果想要很好地回答它们首先你需要了解,我们调整线程池中的线程数量的最主要的目的是为了充分并合理地使用 CPU 和内存等资源,从而最大限度地提高程序的性能。在实际工作中,我们需要根据任务类型的不同选择对应的策略。

2024-04-12 14:46:58 294

原创 11、为什么java不应该用Executors 自动创建线程池?

FixedThreadPool、SingleThreadPool:使用的是无界队列(LinkedBlockingQueue),当任务堆积很多时,会占用大量内存,最终导致OOM。ChachedTheadPool:可以无限创建线程(Integer.MAX_VALUE),任务过多时会导致创建线程达到操作系统上线或者发生OOM。ScheduledThreadPool、SingleThreadScheduledPool:使用的是DelayedWorkQueue队列,实质上也是一种无界队列,会导致OOM。

2024-04-12 13:57:53 783

原创 10、线程池中最常见的阻塞队列类型

在本课时我们主要学习线程池内部结构,以及线程池中最常见的阻塞队列类型。

2024-04-11 22:25:56 522

原创 9、java常见的 6 种线程池详解

总结上述的五种线程池,我们以核心线程数、最大线程数,以及线程存活时间三个维度进行对比,如表格所示。第一个线程池 FixedThreadPool,它的核心线程数和最大线程数都是由构造函数直接传参的,而且它们的值是相等的,所以最大线程数不会超过核心线程数,也就不需要考虑线程回收的问题,如果没有任务可执行,线程仍会在线程池中存活并等待任务。

2024-04-11 20:20:36 932

原创 8、线程池的拒绝策略

线程池任务拒绝策略实现了 RejectedExecutionHandler 接口,JDK 中自带了四种任务拒绝策略。1. AbortPolicy:这种策略会抛出一个 RejectedExecutionException 异常,捕获异常之后可以根据业务逻辑选择重试或提交等策略;2. DiscardPolicy:直接丢弃,存在一定的风险,可能会造成数据丢失,不建议使用。3. DiscardOldestPolicy:丢弃就最旧的任务,同样存在风险,可能会造成数据丢失,不建议使用。

2024-04-10 22:20:58 753

原创 7、线程池各参数的含义详解

本课时我们主要学习线程池各个参数的含义,并重点掌握线程池中线程是在什么时机被创建和销毁的。

2024-04-10 20:57:32 1022

原创 6、Condition和Object 的 wait() /notify() 的关系是什么?

首先介绍了 Condition 接口的作用,并给出了基本用法;然后讲解了它的几个注意点,复习了之前 Condition 和 wait/notify 实现简易版阻塞队列的代码,并且对这两种方法,不同的实现进行了对比;最后分析了它们之间的关系。

2024-04-10 20:41:05 686

原创 5、wait/notify/notifyAll 方法的使用注意事项有哪些?

我们来看第二个问题,为什么 wait/notify/notifyAll 方法被定义在 Object 类中?而 sleep 方法定义在 Thread 类中?主要有两点原因:因为 Java 中每个对象都有一把称之为 monitor 监视器的锁,由于每个对象都可以上锁,这就要求在对象头中有一个用来保存锁信息的位置。

2024-04-08 22:45:01 692

空空如也

空空如也

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

TA关注的人

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