标签:细节问题 闲置 调用 非阻塞io 请求 位置 单线程 串行 code
一、什么是进程、线程
在早期的计算机中,从计算机启动到关闭只执行一个程序,这个程序能够访问计算机内的所有资源。在计算机程序启动执行的时候你无法做任何别的事,这种裸机环境中是对资源极大的浪费。
那么这个时候,操作系统就应运而生了。在操作系统中,你可以运行多个应用程序,每个程序运行在独立的进程当中,操作系统通过调度进程,给他们分配时间片并快速切换执行来达到“同时执行”目的。
你可以把进程简单理解为计算机程序的运行,是操作系统基本的调度单位。
那什么是线程呢?我们思考一个问题,计算机为了同时运行多个程序从而产生了进程,那么每个程序是否能够执行多个任务而不是从头到尾只做一件事呢?答案是可以的,这就是线程的意义所在。在大多数现代操作系统中,更多的是以线程为最基本的调度单位,而不是线程。一个进程中包含多个线程,每个线程彼此独立,共享进程当中的时间片、内存空间。和进程一样,线程通过快速的切换来达到“同时执行”的目的。
二、优缺点
优点:
1)发挥多处理器的强大能力
我们都听过多核处理器,那么如果我们的程序只有一个线程,那它最多同时只能利用到一个处理器。如果是双核处理器,那么就有一半的资源闲置。如果有100核的处理器,那么你的程序就浪费了99%的处理器资源。多线程可以让你充分地利用处理器资源,从而使程序获得高性能并发的能力。
2)提高用户界面的响应速度
传统的GUI应用程序是单线程的,你可以预想到,如果一个操作卡住了整个应用程序就卡死在那里。或者你想要下载一个资源,却发现你必须等待在那里直勾勾地看着下载进度慢慢增加而不能挑选更多令自己满意的资源。那么多线程可以帮你解决这个问题,你可以在下载的时候做别的事,挑选更多的资源,它下载完毕以后你再去关注下载好的资源。
3)异步事件简化
在单线程应用中,为了避免一个请求阻塞导致整个程序停顿,通常会采用非阻塞IO的方式,但是这种方式的复杂性远远高于同步的IO,很容易产生错误。那么,如果每个请求都在一个独立的线程当中呢?一个请求的阻塞将和其它请求互不影响,那也就不会发生上面提到的一个请求阻塞整个程序的现象。
4)建模的简单性
如果我们要构建一个很大的模型,那么就很考验你的构建能力。你必须有着丰富的经验,以及尽最大能力保证每个地方都不出错。多线程在这方面提供了帮助,例如:你可以将一个复杂的工作流给分解,每一个组分配在一个单独的线程里运行,并在特定的位置进行交互(其实可以理解为“异步解耦”)。你可能会顾虑到将一个工作流拆分,是否会带来很高的编程复杂性?确实,如果你必须从零开始写所有东西这将会对你的编程能力有着很大的考验。但是我们可以通过一些现有的成熟框架来实现上面的目标,例如:Servlet、RMI等。框架负责大多数线程的细节问题,同步调用你的业务代码,使你的业务代码也具有多线程特性。
缺点:
1)安全性
在并发编程中线程安全是不可破坏的,它对于多线程应用程序非常重要。
我们看一段代码片段
public class Test{ private int i = 1; public void incrI(){ ++i; } }
在单线程情况下,以上的代码不会有什么问题。但是在多线程的情况下你可能会遇到这样的情况:
1、线程1取到值i = 1,线程2取到i = 1;
2、线程1将i + 1 = 2,线程2将i + 1 = 2;
3、线程1赋值 i = 2,线程2赋值i= 2。
我们看到,最终的结果是2,而不是我们预期的结果1 + 1 = 2; 2 + 1 = 3;
所以,多线程在交替执行的时候,由于执行时间上的问题会带来变量操作的安全性问题(结果与预期不符)。
注意:自增自减操作并不是原子操作,例如自增包含了3个动作取值、加法计算、赋值。
2)性能问题
虽然多线程能够充分利用CPU,从一定程度上你也可以理解为提高程序的性能。但区别于串行程序,多线程将会频繁地出现上下文切换,CPU更多地花在线程调度上,以及针对共享数据你需要采用同步机制等,以上这些问题将会给程序带来额外开销。所以多线程程序还需要做的一件事是如何分析和减少这些额外的开销。
3)活跃性问题
什么是活跃性?活跃性意味着你的程序总是能够及时地执行。活跃性问题就是说你的程序无法正确的继续执行,例如:死锁、饥饿、活锁。与大多数并发问题一样,如果发生了活跃性问题,通常是难以解决的,甚至于分析都无从下手,因为他们执行的时间是没有规律的你难以重现发生的问题。
标签:细节问题 闲置 调用 非阻塞io 请求 位置 单线程 串行 code
原文地址:https://www.cnblogs.com/lay2017/p/9277930.html