前言
在做程序员的这俩年内总是在向框架,前沿技术赶着学。现在回顾这段跑着的路程,让我觉得应该慢下来去将自己的过往夯实,再向大厦前行,在这几年的编程过程中发现线程的使用是非常常见的,那么废话不多说直接上正文。
线程同步
我们可能在不同的程度知道,在不同的线程针对一个资源的时候,如果说是对资源进行简单的的读取,那么就不会有什么大问题,但是如果对这个资源进行修改的话,那么就会导致资源冲突
在
并发
的情况下面,指令执行的先后顺序由内核决定,那么用我们理解的语言概括一下就是:计算机自己都无法预测我会先执行哪一个线程任务。那么为了解决这个问题我们常用的解决方法就是将其化成一个原子级事务,那么这个事情也就迎刃而解了。
词
义
解
释
\color{#FF0000}{词义解释}
词义解释
并发:并发是指俩个或者多个事件在同一个时间间隔发生
并行:并行是指俩个或者多个事件在同一时间发生
那么对于多线程的程序来讲,同步的含义就是:在同一个时间内只允许一个线程进行资源访问,那么就有以下几种方法实现:
- 互斥锁
- 条件变量
- 读写锁
- 信号量
互斥锁
互斥锁 是最常见的线程同步方式,它是一种特殊的变量,它有 lock 和 unlock 两种状态,一旦获取,就会上锁,且只能由该线程解锁,期间,其他线程无法获取
互
斥
锁
模
型
\color{#FF0000}{互斥锁模型}
互斥锁模型
当线程进入临界区之前,首先尝试加锁,如果成功,可以进去临界区,如果失败,需要等待。当临界区的代码被执行完毕或者发生异常时,线程释放锁。
当然如果说世界总是这么简单就好了,上面的模型虽然直观但是过于简单,我们现在来考虑以下俩个问题;
- 我们锁的是什么?
- 我们保护的又是什么?
在我们现实时世界里面锁和锁要保护的资源是有对应关系的,通俗的来说讲,你用你家的锁保护你家的东西,我用我家的锁保护我家的东西。
在并发编程里面我们也要学着去探究锁和资源是否也有着这层关系
改 进 互 斥 锁 模 型 \color{#FF0000}{改进互斥锁模型} 改进互斥锁模型
语法
public class test {
// 修饰实例方法
synchronized void Data() {
// 业务代码
}
// 修饰静态方法
synchronized static void updateData() {
// 业务代码
}
// 修饰代码块
Object obj = new Object();
void createData() {
synchronized(obj) {
// 业务代码
}
}
}
我们不用担心执行加锁操作后,忘了解锁操作,因为Java编译器已经自动为我们在synchronized关键字修改的方法或者代码块前后添加了加锁和解锁逻辑。
锁和受保护的资源关系
通俗的来说锁和受保护的资源之间是N:1的关系
- 一个锁可以保护多个对象
- 一个受保护的资源上只能有一个锁
我们可以用车票来做类比,其中车上面固定的座位比做资源,那么一个车票对应的就是一个座位,如果遇到的是包车作为这个对象,那么一张车票就对应着一车的座位,就不会有一个座位对应着多张车票的情况。
同理:在互斥锁的场景下,如果两个锁使用了不同的锁对象,那么这两个所对应的临界区不是互斥的。
这一点很重要,如果忽视他的话,那么就会引发很多并发的问题。
细粒度锁
做一个简单的描述:银行业务中,修改密码,以及取钱业务,从业务来看这俩块业务没有关联,是可以并行的,那么我们就可以创建各自的互斥锁对资源进行保护,那么这样的话,这俩个业务就不会互相影响了,这样的锁也被称为细粒度锁
。