多线程理解

一.多线程在实际项目中的应用
主要是两方面:解决线程安全问题和异步线程
1.解决线程安全问题:主要是针对多线程并发下针对统一数据进行读取,修改,删除等操作时同步问题,即多线程下保持数据的同步一致
(1)实际案例:
A.生成订单的流水号或者订单号时,多线程下防止生成相同的
B.java中多线程下对HashMap的操作,即集合的线程安全问题
C.解决秒杀中商品超卖问题,秒杀抢购商品时,通过查询redis缓存中商品数量是否还有库存来决定是否还能售卖,若此时只剩一个库存,多个线程并发得到这个仅剩一个库存,都下单了,但是只有一个库存,这是就多卖了,出现了超卖问题
(2)解决方法:
A.使用7种线程同步机制来解决线程安全
B.使用Redis的数据队列来解决线程安全

2.异步线程:在主线程中存在着一段不影响业务流程,可以后续处理但必须处理的业务逻辑,此时为了更快返回程序处理的结果,会将不影响业务流程的代码单独存放到一个线程中,进行异步处理。
(1)实际案例:
A.秒杀中,商品已经抢购成功,为了更快给客户反馈抢购的结果,对于生成订单以及修改库存可以进行异步线程处理
(2)解决方法:
A.实际项目中,基本上使用线程池来创建一个异步线程进行执行,对于实际要执行业务逻辑,封装到一个实现了Runable或者Callable接口的任务类,然后在线程池创建线程时,将任务类作为参数传入

二.线程基础
在这里插入图片描述
1.什么是并发与并行?
并发:是指两个或者多个事件在同一时间段发生的
并行:是指两个或者多个事件在同一时刻发生(即同时发生)
在这里插入图片描述
2.什么是进程,线程以及多线程?
(1)进程:正在运行程序的实例,进程是线程的容器,一个进程可以包含多个线程
(2)线程:是进程内部中一个独立的执行单元,一个进程可以同时并发运行多个线程。进程可以理解为医院,那么线程就是挂号,就诊,缴费,拿药等业务活动
(3)多线程:是指多个线程并发运行

3.创建线程的四种方式
所谓java中线程的使用,无非就是通过不同的方式创建出线程类,然后在一段程序执行的时候,实例化这个线程类,得到线程对象,然后调用方法开始这个线程,这样的话就会出现两个线程并发,即主线程与子线程并发执行,产生多线程的效果
(1)继承Thread类
(1.1)创建线程类,继承Thread类,重写run方法即可

在这里插入图片描述
(1.2)主线程调用线程类对象

在这里插入图片描述
(1.3)结果:
在这里插入图片描述

(2)实现Runable接口
(2.1)创建任务类,实现Runable接口,实现run方法即可
在这里插入图片描述
(2.2)自己实例化Thread线程类对象,然后将任务类作为参数传入到Thread线程类对象,然后Thread线程类对象调用start()方法开始执行
在这里插入图片描述
(2.3)结果:
在这里插入图片描述

(3)实现Callable接口(靠包)
FutureTask类的介绍,实现了Runnable接口,因此可作为参数传到Thread类中。实现Future接口,因此可以调用Future接口的方法
在这里插入图片描述
在这里插入图片描述
(3.1)创建任务类,实现Callable接口,实现call方法即可
在这里插入图片描述
(3.2)自己实例化Thread线程类对象,然后将任务类作为参数传入到Thread线程类对象,然后Thread线程类对象调用start()方法开始执行在这里插入图片描述
(4)线程池Executor形式
(4.1)含义:前面三种方式都是自己创建线程对象然后去自己执行,这在实际开发中是不使用,实际开发中基本都是通过线程池形式创建线程。
线程池可以理解为一个装有多个线程对象的容器,用的时候直接从线程池中取出线程对象进行使用,使用完了,然后再放回到线程池中,下次再用
(4.2)线程池类Executor的关系图

在这里插入图片描述
(4.3)代码实现
在这里插入图片描述
4.几种创建线程的比较

4.线程的生命周期
线程包括5个生命状态:新建,就绪,运行,阻塞和结束。
线程生命周期执行流程:new一个线程实例时,此线程处于新建状态,当该线程调用了start()方法后,该线程处于就绪状态,当该线程得到CPU资源,开始运行run()方法后,此线程处于运行状态,在运行状态时当发生三种不同情况后,会转变成不同的状态:(1)当调用yield()方法或者失去CPU资源时,线程状态转回到就绪状态
(2)当调用sleep()方法或者其他4种情况时,线程处于堵塞状态,当sleep()方法时间到或者其他4种情况执行完成后,就会由堵塞状态转变为就绪状态,然后等待CPU资源重新开始等到运行
(3)当线程的run()方法执行完毕或者发生异常或者调用stop()方法,导致线程运行结束,此时线程处于结束状态
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
5.线程安全问题
(1)线程安全的含义
在这里插入图片描述
(2)线程安全产生的原因?
根本原因:多个线程对同一个全局变量或者静态变量同一时段内进行写操作时,产生线程安全问题
在这里插入图片描述
采用多线程模拟多个窗口同时售卖电影票演示线程安全问题:
在这里插入图片描述
在这里插入图片描述
第二步:创建测试类
在这里插入图片描述
(3)线程安全的解决方式?
只要在某个线程修改共享资源的时候,其他线程不能修改资源,等待修改完毕同步后,其他线程才能去抢夺CPU资源,完成对应的操作,保证了数据的同步性,解决线程不安全的现象。
因此java引入7种线程同步机制来解决线程安全问题。
在这里插入图片描述
(4)同步代码块
同步代码块是代码级别的,分两步:定义锁对象(可理解为谁获得锁就可以操作,否则只能等待)和synchronized(锁对象){执行代码}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(5)同步方法
同步方法是方法级别的,在方法添加上关键字synchronized即可
在这里插入图片描述
注意:同步方法实际上同同步代码块一样存在锁对象,只不是自动默认生成并隐藏
(一)非静态方法:锁对象是同步方法所在类的对象
(二)静态方法(带有static关键字的):锁对象是同步方法所在类的字节码对象即类.Class
(6)同步锁
同步锁的顶级是一个接口Lock,本次使用Lock的一个实现类重入锁ReenreantLock为例,来使用同步锁来解决线程安全问题
在这里插入图片描述
注意:使用同步锁一般分两步:(一)定义锁对象,采用Lock接口接收锁对象
(二)同步锁对象的加锁和解锁方法是配套使用的,使用了加锁方法不使用解锁方法容易造成死锁,控制线程安全的代码在加锁和解锁方法之间,使用Lock来控制线程安全一般try{}finally{},其中加锁方法在try{}方法外,代码在try{}中,解锁方法中finally{},这样做的目的,无论代码是否发生异常,finally{}必须执行,为避免不能释放锁造成死锁
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(7)synchronized和Lock的区别

在这里插入图片描述

6.死锁
(1)死锁的含义:
在这里插入图片描述
(2)死锁产生的必要条件
在这里插入图片描述
在这里插入图片描述
说白了,为了解决线程安全问题,引进锁资源,只用抢占到锁资源的线程才能执行,因此在多线程的情况有可能出现多个线程抢夺资源而造成一种互相等待,处于僵局的情况,即死锁。
死锁产生的必要条件:
A.互斥:资源只能被一个线程所占有,其他线程要想请求只能等待
B.不可剥夺:被占有的资源只能被所占有线程主动放弃,否则其他线程不能抢占到
C.请求与保持:该进程已经占有了至少一个资源,并且同时提出了对其他的资源的请求,但是要请求的资源已被其他线程所占用,即请求了一个被占有的资源,此时请求的资源请求不到造成线程等待堵塞,但是自己所占用的资源不进行释放
D.循环等待:如上图

(3)死锁的处理
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
7.线程通讯
在这里插入图片描述

(1)为什么需要线程通讯?
在多线程的情况下,线程的执行者是CPU,默认情况下CPU是随意切换线程的,即在一段时间段内,这段时间执行线程1,在线程1未执行完的情况下,CPU接着切换到线程2,在线程2执行未完成的情况下,又切换到线程1进行执行。
目的:为了让多个线程的执行按照我们的顺序执行,这时需要线程之间的通讯来确定执行的规律和顺序

(2)线程的通讯方式?
(2.1)使用Object的wait(),notify()方法进行线程通讯
大概思路:调用wait()方法时,当前执行的线程进行等待。当调用notify()方法时,通知其他线程进行执行,这样一等待一通知就可以确定线程的执行顺序。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2.2)使用Condition的await(),signal()方法进行线程通讯
在这里插入图片描述

三.线程高级篇
在这里插入图片描述
1.Java的内存结构
2.多线程三大特性
要想进行多线程编程必须满足三大特性:原子性,可见性和有序性
在这里插入图片描述
3.多线程控制类
为了保证多线程的三大特性,Java引进了很多线程控制机制,下面介绍常用的几种:
在这里插入图片描述
(1)ThreadLocal线程本地变量
即多线程下每个线程自己独有的线程本地变量,线程之间互不影响。

在这里插入图片描述
在这里插入图片描述
代码大体思路:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ThreadLocal的原理:
在这里插入图片描述

(2)原子类
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所谓原子类,就是在多线程对相同变量进行操作的情况下,
一个线程在对变量没操作完成情况下,其他线程对该变量进行了操作,这样就导致了数据混乱。
可通过原子类对变量进行定义并采用原子类提供的方法进行操作,这样就保证了每个线程对该变量进行全部操作后,其他线程才可进行操作
在这里插入图片描述
在这里插入图片描述
原子类的原理:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值