跟我学代码架构设计模式之--锁和线程的补充

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w1857518575/article/details/85258095

本文讲讲对理解锁和线程有帮助的一些零散的点~

#  再思考线程的本质

首先理解一点:线程会阻塞,CPU永远不会阻塞,除非电脑休眠!CPU一直在循环的忙碌执行指令,不会阻塞!

在CPU的角度上看,线程其实就是一个个的数据对象!这个数据对象包含了CPU要执行的代码的CPU寄存器(包括堆栈位置相关的寄存器)信息,也就是线程上下文信息,另外还应该包含线程相关的一些状态数据,比如优先级和线程状态等!我们的线程会阻塞和恢复执行,完全是因为CPU永远不会休息!

线程阻塞了是因为CPU当前时段不执行这个线程上下文了,而是选择了其他上下文去执行;线程又恢复执行了是因为CPU又把该线程的上下文切换回来继续执行了。

本质上,我们的线程的调度都是由于“上帝之手”的存在---永不停歇运转的CPU和硬件定时器的持续运转!

CPU说:执行哪个线程的上下文代码都一样,我一直是顺序执行指令的的,对于我来说我只是“跳着”执行内存不同地方的代码让你们误认为我是并行的而已,你们感受到并行都是我虚构出的~

# 设计的角度分析下锁

对于一个多线程并发环境下有关联资源的函数,在函数代码编写角度上,给函数加锁实际上相当于面向界面编程AOP理念--即锁可以单独被实现,然后被介入到各种函数的执行过程中去!说白了,按照面向对象的思想,锁可以单独实现为各种类!锁这些个类相当于把“资源保护”这个公共的逻辑抽出来,这样我们编写需要资源保护的函数的时候,直接调用锁相关的操作就可以了~

# 面向对象的角度分析锁对象应该如何设计

首先,我们先进行简单需求分析:

首先 锁是为了保护资源访问而协调线程执行顺序,所以应该有状态数据来确保当前允许和禁止哪些线程执行;

其次,锁(自旋锁应该除外)应该还能阻塞得不到锁状态的线程,所以应该有个阻塞队列,得不到锁的线程对象应该被放进阻塞队列中等待;

上面说的状态和阻塞队列是锁对象的数据,是多个线程共享的数据。此外锁还应该提供如下的操作方法:

1 获得锁方法,方法实现为:原子的判断锁状态(因为锁数据本身也是共享的,需要保护),如果当前线程获取不到锁,应该把该线程设置为阻塞状态,并放入锁的阻塞队列中等待。

2 解锁方法:获得锁的线程原子的修改锁状态数据来释放锁,同时获取锁的阻塞队列,通知一个线程可以执行(即修改线程对象的状态为运行态,让CPU可以调度到这个线程)。

补充:由于锁本身的状态也是多线程共享的数据,也需要保护,一般是通过原子的CAS操作,即compare and set 、compare and get、compare and swap,分别对应同步的设置状态数据、获取状态数据和修改状态数据,有了这几个操作作为根本保证,才有了锁可以被单独实现为公共操作类的理论基础~

总结:

1 锁对象应该是多线程共享的

2 锁对象应该有状态数据

3 锁对象应该有阻塞队列

4 CAS操作确保了锁本身状态的同步修改

(完)

猜你喜欢

转载自blog.csdn.net/w1857518575/article/details/85258095