从头开始学Java并发
文章平均质量分 59
本专栏系统地梳理了Java并发的核心知识点,并对其进行讲解和演示。
lwen.steven
学好Java,为公司“添砖加瓦”!
展开
-
22.高并发秒杀
高并发秒杀场景,通过分布式锁解决超卖以及一人多单问题。原创 2023-03-30 22:09:44 · 251 阅读 · 0 评论 -
21.CompletableFuture
1.使用场景 (1).提交任务 runAsync:无返回值 supplyAsync:有返回值 (2).两个任务编排 thenRunAsync:不能接收上一次的执行结果,也没返回值 thenAcceptAsync:能接收上一次的执行结果,但没返回值 thenApplyAsync:能接收上一次的执行结果,又可以有返回值 (3).三任务编排 runAfterBothAsync:前两个任务都完成,才执行任务3,不感知任务1、2的结果,也没返回值 thenAcceptBothAsync:前两个任务都完成,才执行任原创 2023-03-27 10:22:46 · 178 阅读 · 0 评论 -
20.AQS
1.概念 AQS(AbstractQueuedSynchronizer),是一个用于构建锁、同步器、协作工具类的框架。 2.三要素 (1).state 根据具体实现类的不同显示不同的含义,如CountDownLatch类表示还需要倒数的数量,Semaphore类表示剩余许可证,ReentrantLock类中表示重入次数。 (2).控制线程抢锁和配合的FIFO队列 队列是用来存放等待的线程,当多个线程竞争同一把锁时,只有一个线程获取锁,其它线程就会被封装node结点加入到队列中,当锁被释放时,AQS就需要原创 2023-01-06 17:56:01 · 89 阅读 · 0 评论 -
19.CAS
1.概念 CAS(Compare And Swap)是一个特殊的CPU指令,可以保证原子性。 多个线程操作共享数据,一个线程获取操作权后,不会给共享数据加锁,它会先记录一下共享数据的值,等待执行完毕后,该线程会判断共享数据的值有没有发生变化,如果没有发生变化,则该线程才会去修改,如果发生变化则该线程不进行此次修改。 CAS有三个操作数,内存值、预期值和修改值,只有当内存值和预期值相等时,才会将修改值写入内存。如果内存值和预期值不相等时,说明有线程修改了值,则此次修改失败,返回内存值。允许失败的线程进行重试,原创 2023-01-06 17:54:46 · 87 阅读 · 0 评论 -
18.锁机制
过程:多个线程操作共享数据,一个线程获取操作权后,不会给共享数据加锁,它会先记录一下共享数据的值,等待执行完毕后,该线程会判断共享数据的值有没有发生变化,如果没有发生变化,则该线程才会去修改,如果发生变化则该线程不进行此次修改。线程会通过自旋来获取锁资源,如果获取到,则仍然为轻量级锁,如果没有获取到,则轻量级锁膨胀为重量级锁。概念:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,饥饿的状态(某个线程一直得不到锁)。原创 2023-01-06 17:54:23 · 97 阅读 · 0 评论 -
17.并发工具类
模拟100米跑步,5名选手都准备好了,只等裁判员一声令下,所有人同时开始跑步。当所有人都到终点后,比赛结束。使用await()和signal()必须先获取锁,与wait()和notify()必须先获取锁一样。(3).CyclicBarrier和CountDownLatch区别。多个运动员跑步需要等待一个裁判的发令枪,发令枪响,运动员可以出发。一个零件需要5个人质检,只有等5个人质检完才可以进入下一个阶段。(2).游乐场游客摆渡车每满5人便发车场景。(2).耗时任务等待许可证场景。(4).综合用法场景。原创 2023-01-06 17:50:33 · 94 阅读 · 0 评论 -
16.Atomic
1.原子类 (1).概念 一个操作是不可中断的,即要么同时执行,要么同时不执行。 (2).好处 粒度更细:原子变量可以把竞争范围缩小到变量级别。 效率更高:除了高度竞争的情况,原子类比锁具有更高的效率。原创 2023-01-06 17:48:21 · 82 阅读 · 0 评论 -
15.ThreadLocal
1.使用场景 每个线程需要一个独享的对象,通常是工具类,如SimpleDateFormat和Random。 每个线程内需要保存全局变量,例如在拦截器中获取用户信息,让不同方法直接使用,避免参数传递的麻烦。原创 2023-01-06 17:46:14 · 74 阅读 · 0 评论 -
14.获取子线程结果
1.Runnable (1).缺陷 没有返回值 不能抛出一个检查异常 2.Future (1).作用 Future是一个存储器,它存储了Callable这个任务的执行结果,而这个任务的执行时间无法提前确定,取决于call()方法的执行情况。 (2).isDone() 判断线程是否执行完毕,但并不能保证任务是否成功被执行。原创 2023-01-05 14:13:10 · 245 阅读 · 0 评论 -
13.线程池
1.为什么要使用线程池 (1).每个任务都新开一个线程处理 上述代码开启10个线程执行任务,但是如果任务数上升为1000个或者10000个,那么再开启1000个或者10000个线程去执行显然不合理,因为线程的创建和销毁是很消耗系统资源的。所以引入线程池可以避免反复创建和销毁线程,增加系统的开销。第二是过多的线程会占用内存,会抛出OOM。原创 2023-01-05 14:13:42 · 226 阅读 · 1 评论 -
12.底层原理之重排序
1.简介 在线程内部的两行代码的实际执行顺序和代码在Java文件中的顺序不一致,代码指令并不是严格按照代码语句顺序执行,这种特性被称之为重排序。重排序的好处是可以提高程序的处理速度。原创 2023-01-05 14:13:30 · 108 阅读 · 0 评论 -
11.底层原理之可见性
1.简介 一个线程对主内存的修改能够及时地被其他线程观察到,这种特性被称之为可见性。原创 2023-01-05 14:12:33 · 150 阅读 · 0 评论 -
10.底层原理之原子性
1.简介 一系列的操作,要么全部执行成功,要么全部不执行,不会出现执行一半的情况,是不可分割的,这种特性被称之为原子性。原创 2023-01-05 14:13:02 · 222 阅读 · 0 评论 -
9.底层原理
1.底层原理简介 在早期,JVM会将相同的.class文件(字节码文件)翻译成不同的机器指令,在不同操作系统的平台上,无法保证一致的并发安全。因此,需要有一个规范来保证安全一致的并发安全效果。 2.JVM内存模型 JVM内存模型是和Java虚拟机运行时区域相关的结构,其结构图和各结构作用如下。原创 2023-01-04 21:35:17 · 174 阅读 · 0 评论 -
8.线程安全
假如线程thread0进入到for循环内,但是还没有赋值就让出了CPU执行权,线程thread1获取CPU执行权开始执行线程任务,获取的index值会和前一步thread0获取的一样,就样就会出现index漏加的情况。当多个线程访问一个对象时,如果不用考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方未进行任何其它协调操作情况下,调用这个对象的行为都可以获得正确结果,那么这个对象便是线程安全的。指多个线程竞争资源导致互相等待的僵局,如果没有外力的作用,这种现象将一直持续下去。原创 2023-01-04 00:28:17 · 62 阅读 · 0 评论 -
7.线程常用方法
在A线程中调用B线程的join()方法,也就是B线程充当了这把锁,调用者A线程被挂起(谁调用wait谁休眠),当B线程还活着,就一直wait,只有当B线程执行完了,A才会被唤醒。代码运行结果如下所示,其中,第一行和第二行输出顺序可以互换,第四行和第五行输出顺序也可以互换,原因是Thread-0和Thread-1公平竞争CPU资源,哪一个先被分配到CPU执行权,哪一个就先运行。参数:如果传入的时间参数值为0就是永久等待,不为0时,过了wait()方法设置的超时时间,该线程会自动苏醒进入RUNNABLE状态。原创 2023-01-04 00:27:30 · 87 阅读 · 0 评论 -
6.线程状态
执行结果如下所示,在线程创建后未调用start()方法前,线程状态为NEW,调用start()方法后,线程状态为RUNNABLE。然后执行子线程任务,在执行过程中打印线程状态依然为RUNNABLE,最后线程执行完毕后,线程状态为TERMINATED。如果子线程打印的数值比较少,比如10,那么倒数第二个的线程状态可能为TERMINATED。如线程源码所示,共定义了6种线程状态,NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING以及TERMINATED。程序执行结果如下所示。原创 2023-01-04 00:24:45 · 80 阅读 · 0 评论 -
5.线程异常
程序执行结果如下所示,当Thread1抛出异常时,应当进入catch分支,并终止程序运行。但实际上没有,程序继续运行,4个子线程分别抛出异常,这说明使用try catch没有捕获到子线程异常。2.UncaughtExceptionHandler源码分析。程序执行结果如下所示,4个子线程抛出的异常都被捕获。1.不能用传统方法捕获线程异常。原创 2023-01-04 00:22:45 · 153 阅读 · 0 评论 -
4.线程属性
代码运行结果如下所示,子线程Id不为2的原因是,JVM在运行该程序时,除了创建main线程外,还创建了包括Finalizer、Reference Handler、Signal Dispatcher等线程。答:不应该将线程设置为守护线程,原因是当程序中只剩下守护线程时,JVM便会退出,这将会导致线程任务没有执行完毕。守护线程的作用是给用户线程提供服务的,比如垃圾回收线程。答:守护线程和普通线程的核心区别是能否决定JVM的退出,普通线程会影响JVM的退出而守护线程不会。(1).守护线程和普通线程的区别?原创 2023-01-04 00:20:53 · 77 阅读 · 0 评论 -
3.线程启动
1.正确和错误的实现方式 代码运行结果如下所示,由此可知,启动线程的正确方式是调用start方法。 2.start方法的含义 启动新线程。请求JVM开启子线程的任务,这里需要注意的是,执行start方法后,线程任务并不一定会被立刻执行,何时被执行取决于JVM的调度。 准备工作。使线程处于就绪状态,准备除CPU执行权以外的所有资源,如内存和程序运行时的上下文环境。 不能重复执行start方法。执行start方法前,需要检查线程的状态,如果不是0,则会抛出线程状态异常IllegalThreadStateExce原创 2023-01-04 00:18:47 · 73 阅读 · 0 评论 -
2.线程实现
1.实现线程的方式 Oracle官方文档阐述了两种实现线程的方式,一种是实现Runnable接口并重写run方法,另一种是继承Thread类并重写run方法,两种实现方式的代码分别如下所示。原创 2023-01-04 00:16:19 · 70 阅读 · 0 评论 -
1.并发编程简介
1.操作系统、进程和线程 (1).操作系统 操作系统指的是管理计算机硬件与软件资源的计算机程序。 (2).进程 进程指的是程序的一次执行,是程序的真正运行实例,是资源分配的基本单位,在用户下达运行程序的命令后就会产生进程。 (3).线程 线程指的是CPU的基本调度单位,每个线程执行的都是进程代码的某个片段。 (4).三者的关系 操作系统是包含一个或多个进程的容器,而进程是包含一个或多个线程的容器。原创 2023-01-04 00:13:30 · 98 阅读 · 0 评论 -
从头开始学Java并发
1.并发编程简介 2.线程实现 3.线程启动 4.线程属性 5.线程异常 6.线程状态 7.线程常用方法 8.线程安全 9.底层原理 10.底层原理之原子性 11.底层原理之可见性 12.底层原理之重排序 13.线程池 14.获取子线程结果 15.ThreadLocal 16.原子类 17.并发工具类 18.锁机制 19.CAS 20.AQS原创 2023-01-04 00:13:18 · 83 阅读 · 0 评论