(一)、必须知道的几个概念
1.1 同步和异步
同步和异步都是用来形容一次方法调用。主要的区别是同步方法调用一旦开始,就必须等待调用的方法返回之后才能继续执行下面的程序。而异步调用则无需等待调用的方法返回,调用之后就可以立即执行下面的语句,当调用的方法返回之后会通知调用者。举个例子,你去商场购买空调,你和销售员说你想买一台空调,于是销售员就安排师傅把空调送到你家里去,等空调安装上了你才付钱,这个是同步调用。另一种方式你和销售员说你要买空调,销售员于是安排师傅送空调给你,在师傅送空调的时候,你就把钱给付了,这就是异步调用
1.2 并发和并行
并发和并行其实是两组概念。并行的意思是多个任务真正的同时执行。而并发则是多个任务之间交替执行。如果是单核CPU,那么就无法实现并行执行程序。
1.3 临界区
临界区可以用来表示一种共享资源,可以被不同的线程使用。但是在某一时刻,只能被某一个线程使用,其他线程在这个时候想要使用,那就只能挂起,等待该线程离开临界区,才能使用临界区的资源。
1.4 阻塞和非阻塞
阻塞代表一个线程占用了临界区的资源,其他线程想要使用,那就只能将线程挂起,进行等待。非阻塞代表没有一个线程可以阻塞其他线程,所有的线程都尝试使用临界区的资源。
(二)、并发编程的优点
- 并发地执行程序毫无疑问可以提高程序执行的效率,因为程序执行过程中,大部分时间都花费在读取数据上面了,如果是单线程执行,那么就会导致效率低下。并发交替执行程序可以在一条线程在读取数据的时候执行另一条线程的任务,这样就可以大大提高效率。
- 充分利用多核CPU的计算能力,方便进行业务拆分,提升应用性能
(三)、并发编程的缺点
时间片是CPU分给各个线程的时间,这个时间通常非常短,通常只有几十毫秒。CPU在切换线程的时候也是非常迅速的,所以有时给我们的感觉是在并发执行的。但是CPU切换之前,需要保存当前的状态,以便到时可以切换回来。这种切换是非常消耗性能的,所以如果频繁地切换就会十分消耗时间。通常有以下几种方法可以减少上下文的切换。
-
无锁的并发编程
这里可以参考ConcurrentHashMap使用的分段锁机制,不同的锁管理不同的段,这样可以减少上下文的切换。
-
使用CAS算法
大家应该都知道Atomic包下的对象例如AtomicInteger、AtomicReference均使用CompareAndSet来更新数据,这样可以有效地减少锁的竞争,从而减少上下文的切换。
-
使用尽可能少的线程
如果线程过多会大量线程处于等待状态。
-
协程
在单线程里执行多任务调度,并在单线程里实现多个任务之间的切换。
-
线程安全问题
线程安全问题涉及到很多方面,之后的文章再详细介绍。
参考文章:并发编程的优缺点