每个Java应用都涉及到多线程,JVM、Servlet、JSP同理
(一)使用多线程的原因
- 首先要明确什么是线程?
- 线程也被叫做轻量级进程
- 同一个进程内的所有线程都将共享进程的内存空间
- 并发编程增大了编程的难度,让编写出正确的程序变难,那么使用多线程的优势在哪里?
- CPU基本的调度单位是线程,对于多处理器,多线程程序可以同时在多个CPU上运行,提高了硬件的利用率
- 而对于单处理器,在I/O的时间内利用处理器,提高了程序的吞吐率
- 服务器应用程序单线程时只能使用复杂的非阻塞I/O来替代I/O,而多线程能够为每个请求分配线程来解决发生请求对其他请求的处理阻塞问题
- 对于GUI,将事件响应提取出来为一个线程,其他线程在执行长时间操作的时候,事件线程能够对输入进行及时响应,提供了更灵敏的图形界面
(二)使用多线程的风险
- 安全问题:多个线程共享变量导致操作的发生不可预测,产生的结果也不可预测
- 死锁问题:线程之间相互要求对方的资源同时不释放自己的资源,导致永远等待的现象;类似的还有饥饿问题
- 性能问题:线程切换是会带来额外开销的,线程越多,CPU会花更多的时间在线程的切换上而不是每个线程的执行上
(三)多线程中的基本概念
- 同步:调用同步方法之后,必须等待方法执行完毕,才能继续后续的行为
- 异步:调用异步方法之后,调用者可以马上进行后续的行为,不用等待方法的返回值
- 并发:多个任务交替执行,从宏观上来看,多个任务看似是“同时执行的”,其实只是将处理器时间分片,在不同的任务之间快速切换,导致看上去是“同时执行”
- 并行:多个任务在多个处理器上同时进执行,所以可知对于单个处理器来说,不存在并行的概念
- 临界区:同一时刻只能有一个线程访问的公共资源
- 阻塞:假设两个线程需要使用同一个临界资源,一旦一个线程正在使用,另外一个线程就必须要等待这个线程退出临界区,所以自身进入挂起状态
- 非阻塞:所有线程之间不会相互阻塞的状态
- 活锁:资源在任务之间跳动,但是没有一个任务能够执行的现象(区别于死锁,活锁有可能自行解开)