Java 并发编程之挑战
Java 并发编程之挑战
并发编程的目的是为了让程序运行的更快,但是,并不是启动了更多的线程就能让程序最大限度的并发执行。可能会面临诸多挑战:比如上下文切换问题、死锁问题,以及受限于硬件和软件的资源限制问题。
1.1 上下文切换
即使是单核处理器也支持多线程执行代码,CPU通过分配时间片来实现这个机制;每个时间片执行时间很短,让我们感觉就像是多个线程同时执行,一般是几十毫秒。
CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片过后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回来可以再加载这个状态。所以,任务从保存到再加载的过程就是一个上下文切换。但是上下文切换会有一个的开销。所以我们会尽量减少上下文切换。通常有的方法是:无锁并发编程、CAS算法、使用最少的线程和使用协程。
1.2 死锁
多线程编程难免会遇到多个线程竞争同一资源,此时我们常用的是加锁。等获取锁的线程释放锁过后才能让其他的线程获取锁,但是如果两个线程都在等待对方释放锁,这时就引起了死锁。
一旦出现死锁,业务是可感知的,因为不能继续提供服务了,那么只能通过dump 线程查看到底是哪个线程出现了死锁。
避免死锁的常用方式:
避免一个线程同时获取多个锁;
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源;
尝试使用定时锁,使用lock.tryLock(timeout)来替换使用内部锁机制;
对于数据库锁,加锁和解锁必须要在一个数据连接里面,否则会出现解锁失败的情况。
1.3 资源限制
(1)什么是资源限制
资源限制是指在进行并发线程时,程序的执行速度受限于计算机的软硬件资源。在并发编程时一定要考虑这些限制条件。硬件资源如带宽的上传和下载、硬盘读写速度和CPU的处理速度等。软件资源如数据库的连接数和Socket的连接数等。
(2)资源限制引发的问题
在并发编程时,将代码执行速度加快的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行代码并发执行,因为受限于资源,仍然在串行执行,这时候程序反而更慢,因为增加了上下文切换时间和资源调度的时间。