最近工作用到多线程,接下来就说一下多线程。
多线程也算是java里面一块很重要的内容。说到线程,就不得不谈一谈进程。我们启动电脑的任务管理器时,里面就有一栏——进程,一个进程可以开启多个线程,线程算是轻量级的。不过64位的java虚拟机,默认,一个进程开启的线程占用空间1024K,所以还是有限制的。
谈到多线程的好处,最多的感受可能就是让程序运行得更快,试想让多个线程去执行一个任务,那么肯定比一个线程去执行一个任务要快,就像一个人建一栋房子肯定比许多人建一栋房子要慢。但是事实却并不是如此。启动更多的线程并不一定就能让程序更快的运行。它也受各种限制。比如说:上下文切换的问题,死锁的问题以及受限于硬件和软件资源的限制等。
上下文切换
早期的计算机都是单核处理器,但是它也支持多线程,那么试想一下,如果在单核处理器上编写多线程程序,那么处理器实际上是如何运行的呢?CPU通过给每个线程分配CPU时间片来实现多线程机制。这里解释一下时间片的概念。时间片就是CPU分配给各个线程的时间。因为分配给各个线程的时间非常的短,所以CPU通过不停的切换程序执行,从而让我们感觉就像多个线程同时执行一样,时间片一般也是有几十毫秒,相对于人的感观来说可以忽略不计了,这也就是我们电脑虽然是双核或者四核,但是我们运行几个程序,还是觉得这几个程序可以一起运行的样子。
那么多线程就一定很快吗?这个答案想必都猜到了,不一定。试想一下这个场景。一个小餐厅,配备一名服务员,如果这家餐厅的销售不景气,人流量不高,最多也只有三个人同时就餐,那么一名服务员是完全足够的,如果这个餐厅的老板非要招五名服务员,那么肯定造成服务员的闲置,也就是资源的浪费,这样也并没有提升服务的效率。再想一下,如果这个餐厅的销售很好,每天客流量最高有三十人,这时只配置两名服务员,这会造成什么问题,客人就餐等待时间很长,服务员太少。同理,对线程也是如此。
那么如何让线程快起来呢?
减少上下文的切换,就是将某一块区域的几名客人指定给一名服务员服务。主要方式有:无锁并发编程、CAS算法、使用最少的线程和使用协程。
接下来说一下死锁。
在进行并发编程时,我们常常会使用锁,在使用锁的过程中,如果对锁的使用不够熟练的话,出现死锁也是经常遇到的问题。那么如何避免死锁:
避免一个线程同时获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
- 尝试使用定时锁,使用lock.tryLock(timeout)来替换使用内部锁机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里。否则会出现解锁失败的情况