高并发编程的核心思想是:保证程序运行时关键数据在多线程中的可见性、核心业务的原子性、多线程通信的有序性。
首先需要了解什么是并发什么是并行
什么是并发:
同一时刻同一服务器发生多个相同的事件就是并发,比如很多人春节同一时间抢票对于服务器来说就是并发,比如多人同一时间在双十一剁手对于服务器来说就是并发。
什么是并行:
同一时刻多个服务器发生的事件就是并行,比如春节抢票同一时间别人在抢票你也在抢票对于你和别人来说就是并行,比如双十一剁手同一时间别人在在买你也在买对于你和别人来说就是并行。
并发和并行概念很容易混淆,需要注意。
好了解完什么是并发之后我们来看两张图,两张图分别是Java运行时、简易并发原理:
多线程中的可见性
为何会产生可见性问题:
由于线程是由CPU创建的,CPU创建时会将堆内存中部分对象缓存至自己的缓存区中,这当前线程运行期间如果有其它线程操作了该对象,就会由于数据不一致导致程序出现问题。
如何解决可见性问题:
一、使对象不能被CPU缓存:使用volatile、synchronized关键字
二、使对象无法被修改:枚举enum、全局不可变量final、手动编写一个不可被改变的对象
核心业务的原子性
何为原子性:逻辑上不可被拆分的操作
为何会产生原子性问题:线程与线程之间是不可见的,同一任务在多个线程中并行的被执行,最终得到执行结果,这是多线程的优势也由此产生了原子性问题。
如何解决原子性问题:
一、在外部对象上赋予多线程原子性:使用synchronized关键字、Lock相关类在执行核心业务时通过使用锁定对象的方式变相将多线程暂时变为单线程。
多线程通信的有序性
有序性:若A事件发生是B事件发生的充分条件,那么我们称先发生A事件再发生B事件为有序,反之无序。
为何会产生有序性问题:线程与线程之间是不可见,并行的,也就是说B事件发生过程中无法确认A事件是否发生。
如何解决有序性问题:
一、线程间协作使事件B在A发生前阻塞等待,在事件A发生后唤醒事件B。可以使用锁定对象的wait---notify---notifyAll、灵活一点可以使用lock.newCondition()和 countdownlatch 等方式。
可能有一点不好理解,我写了一篇故事可能会对你有帮助。