共计 2129 个字符,预计需要花费 6 分钟才能阅读完成。
并发编程的优缺点
在计算机科学和软件工程中,并发编程是一种波及同时解决多个工作的技术。它被广泛应用于各种零碎和利用中,如多线程利用、网络服务器和实时零碎等。然而,只管并发编程具备许多长处,但也有一些潜在的毛病须要审慎解决。
长处
- 通过并发编程的模式能够将多核 CPU 的计算能力施展到极致,进步性能。
- 避免阻塞,进步响应性
- 加强可扩展性
- 不便业务拆分,进行业务建模
毛病
- 频繁的上下文切换
- 活跃性问题。可能会产生长时间的期待锁,甚至是死锁。
- 性能问题。线程的频繁调度切换会浪费资源,同步机制会导致内存缓冲区的数据有效,以及减少同步流量。
工夫片是 CPU 调配给各个线程的工夫,因为工夫十分短,所以 CPU 一直通过切换线程,让咱们感觉多个线程是同时执行的,工夫片个别是几十毫秒。而每次切换时,须要保留以后的状态,以便可能进行复原先前状态,而这个切换时十分损耗性能,过于频繁反而无奈施展出多线程编程的劣势。通常缩小上下文切换能够采纳无锁并发编程,CAS 算法,应用起码的线程和应用协程。
无锁并发编程:能够参照 concurrentHashMap 锁分段的思维,不同的线程解决不同段的数据,这样在多线程竞争的条件下,能够缩小上下文切换的工夫。
CAS 算法,利用 Atomic 下应用 CAS 算法来更新数据,应用了乐观锁,能够无效的缩小一部分不必要的锁竞争带来的上下文切换
应用起码线程:防止创立不须要的线程,比方工作很少,然而创立了很多的线程,这样会造成大量的线程都处于期待状态
协程:在单线程里实现多任务的调度,并在单线程里维持多个工作间的切换因为上下文切换也是个绝对比拟耗时的操作,所以在 ”java 并发编程的艺术 ” 一书中有过一个试验,并发累加未必会比串行累加速度要快。能够应用 Lmbench3 测量上下文切换的时长 vmstat 测量上下文切换次数。
线程平安
什么是线程平安
如果你的代码在多线程下执行和在单线程下执行永远都能取得一样的后果,那么你的代码就是线程平安的。
线程平安产生的起因:正确性取决于多个线程的交替执行时序,产生了竞态条件。
线程安全级别
1)不可变
像 String、Integer、Long 这些,都是 final 类型的类,任何一个线程都扭转不了它们的值,要扭转除非新创建一个,因而这些不可变对象不须要任何同步伎俩就能够间接在多线程环境下应用
2)相对线程平安
不论运行时环境如何,调用者都不须要额定的同步措施。要做到这一点通常须要付出许多额定的代价,Java 中标注本人是线程平安的类,实际上绝大多数都不是线程平安的,不过相对线程平安的类,Java 中也有,比方说 CopyOnWriteArrayList、CopyOnWriteArraySet
3)绝对线程平安
绝对线程平安也就是咱们通常意义上所说的线程平安,像 Vector 这种,add、remove 办法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个 Vector、有个线程同时在 add 这个 Vector,99% 的状况下都会呈现 ConcurrentModificationException,也就是 fail-fast 机制。
4)线程非平安
这个就没什么好说的了,ArrayList、LinkedList、HashMap 等都是线程非平安的类,点击这里理解为什么不平安。
多线程编程中最难以把握的就是临界区线程平安问题,略微不留神就会呈现死锁的状况,一旦产生死锁就会造成零碎性能不可用。
通常能够用如下形式防止死锁的状况:
- 防止一个线程同时取得多个锁;
- 防止一个线程在锁外部占有多个资源,尽量保障每个锁只占用一个资源;
- 尝试应用定时锁,应用 lock.tryLock(timeOut),当超时期待时以后线程不会阻塞;
- 对于数据库锁,加锁和解锁必须在一个数据库连贯里,否则会呈现解锁失败的状况
易混同的概念
同步 VS 异步
同步和异步通常用来形容一次办法调用。同步办法调用一开始,调用者必须期待被调用的办法完结后,调用者前面的代码能力执行。而异步调用,指的是,调用者不必管被调用办法是否实现,都会继续执行前面的代码,当被调用的办法实现后会告诉调用者。比方,在超时购物,如果一件物品没了,你得等仓库人员跟你调货,直到仓库人员跟你把货物送过来,你能力持续去收银台付款,这就相似同步调用。而异步调用了,就像网购,你在网上付款下单后,什么事就不必管了,该干嘛就干嘛去了,当货物达到后你收到告诉去取就好。
并发与并行
并发和并行是非常容易混同的概念。并发指的是多个工作交替进行,而并行则是指真正意义上的“同时进行”。实际上,如果零碎内只有一个 CPU,而应用多线程时,那么实在零碎环境下不能并行,只能通过切换工夫片的形式交替进行,而成为并发执行工作。真正的并行也只能呈现在领有多个 CPU 的零碎中。
阻塞和非阻塞
阻塞和非阻塞通常用来形容多线程间的相互影响,比方一个线程占有了临界区资源,那么其余线程须要这个资源就必须进行期待该资源的开释,会导致期待的线程挂起,这种状况就是阻塞,而非阻塞就恰好相反,它强调没有一个线程能够阻塞其余线程,所有的线程都会尝试地往前运行。
临界区
临界区用来示意一种公共资源或者说是共享数据,能够被多个线程应用。然而每个线程应用时,一旦临界区资源被一个线程占有,那么其余线程必须期待。