1.5 多线程的代价
从一个单线程的应用到一个多线程的应用并不仅仅带来好处,它也会有一些代价。不要仅仅为了使用多线程而使用多线程。而应该明确在使用多线程时能多来的好处比所付出的代价大的时候,才使用多线程。如果存在疑问,应该尝试测量一下应用程序的性能和响应能力,而不只是猜测。
设计更复杂
虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般都更复杂。在多线程访问共享数据的时候,这部分代码需要特别的注意。线程之间的交互往往非常复杂。不正确的线程同步产生的错误非常难以被发现,并且重现以修复。
上下文切换的开销
当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针 等,最后才开始执行。这种切换称为“上下文切换”(“context switch
”)。CPU会在一个上下文中执行一个线程,然后切换到另外一个上下文中执行另外一个线程。
上下文切换并不廉价。如果没有必要,应该减少上下文切换的发生。你可以通过维基百科阅读更多的关于上下文切换相关的内容:
http://en.wikipedia.org/wiki/Context_switch
如果你使用的是Linux操作系统,你可以通过vmstat
命令查看当前操作系统每秒的上下文切换次数:
命令"vmstat 1 10
"的含义是:每个1秒统计一次,统计10次后结束。其中cs
那一列表示的就是上下文切换次数,cs是context switch的简写。可以看到目前操作系统系统上每秒上下文切换次数大致都在400-600之间(注意:第一次统计是不准的,而且这个统计是操作系统层面的)。关于其他显示的内容,不是本教程的讲解范围,感兴趣的读者可以阅读其他的参考资料。
增加资源消耗
线程在运行的时候需要从计算机里面得到一些资源。除了CPU,线程还需要一些内存来维持它本地的堆栈。它也需要占用操作系统中一些资源来管理线程。 我们可以尝试编写一个程序,让它创建100个线程,这些线程什么事情都不做,只是在等待,然后看看这个程序在运行的时候占用了多少内存。(代码...)
事实上类似于每个进程启动后,操作系统都要给其分配一定的内存类似,每一个线程启动后,进程也要给线程分配一定的内存,让其来保存自己的私有数据。JVM划分给每个线程的内存区域称之为线程栈内存
。默认情况下,栈内存的大小1M。也就是说,你每多启动一个线程,至少要多消耗1M的内存资源。