漫谈并发编程(一) - 并发简介

来源:互联网 发布:mac资料库 编辑:程序博客网 时间:2024/05/22 06:29
      并发编程是每个程序员进阶的必修之课,想写一个安全稳定,性能强劲的并发程序可没那么容易。我将在未来的日子里,与大家分享一个并发小白成长路上的所思所想。并发编程的思想是通的,但是例子得要是具现的,在该系列中将使用java语言用以演示。
     此文作为为漫谈并发编程系列的第一篇,探本溯源,以一篇对并发的文字描述开头。

并发编程由来

     早年的计算机中没有操作系统,在某个时间段内只支持运行一个程序,并且这个程序能访问计算机的所有资源。在这个程序完全执行完后,再执行下一个程序。

    在此时,引入并发编程的好处:
  • 高效性:计算机的各个部件不用忙等,例如一个程序在使用IO的时候,CPU可以给另外一个程序使用。这样便提高了设备的使用率。
  • 公平性:计算机上运行的程序应该一视同仁,而不是某一个先执行完后,再让另外一个程序开始执行。
  • 便利性:在计算多个任务时,应该编写多个程序,必要时,让其互相通信,这比让一个程序来实现多个任务要更容易实现。
     并发编程最早的体现是多进程的并发编程,这是由操作系统的出现而引入的。多进程的并发编程解决了进程独占计算机全部设备的问题,提升了计算机的吞吐量。可以想象在这种情况下任意时刻的计算机设备与正在运行的进程的对应关系的是一对一,如图所示:。如果当前运行进程较少,系统的很多设备依然会处于空闲状态,此时,使用线程可以进一步提高计算机的处理效率,线程允许一个进程中有多个程序控制流,那么一个进程的多个线程就能同时运行在多个设备上,如图所示:,所以使用线程能进一步提升系统的吞吐量及处理效率。而现在,随着摩尔定律的实现重任逐渐由单cpu的性能增加转移到cpu数量的增加,如何提高多cpu的资源利用率变得非常重要,这些原因促使线程的并发编程越发重要。(从以上分析来看,要从底层提升多线程程序的性能可以使多个线程能够同时运行在多个设备上。)

建模的简单性
     线程除了能够提升性能,还可以将复杂并且异步的工作流进一步分解为一组简单并且同步的工作流,每个工作流在一个单独的线程中运行,并在特定的同步位置进行交互。这一条实际影响了多线程技术的使用场景,即通常将逻辑上或物理上独立的任务用多线程技术来实现(如计算任务与IO任务),而非在程序里相互交错。

线程带来的风险

  • 安全性问题:在很多时候,线程间并不是完全独立的,而是相互协作去共同完成一个task,因此可能需要共同的去访问一个或多个资源,当线程之间没有正确的进行协作时,可能会导致单个资源混乱或者多个资源间存在数据一致性的问题。
  • 活跃性问题:有时往往需要控制多个线程的执行顺序,例如一个线程去读IO,另一个线程从上一个线程中取,因此我们需要将线程进行同步的控制。线程间的协作,容易导致死锁、饥饿等问题。由此线程就会变得不"活跃"。
  • 性能问题:频繁的线程切换、同步机制(经常抑制编译器优化,使内存缓存区的数据无效)。在这里提出一个问题:线程是可以执行一些复合操作的,在使用方式上与进程差异不大,为什么我们不在线程的基础上进一步的细分,比如搞出一个比线程更细的调度单位"小线程",这样的话程序的执行效率不会更高吗?答:这样会进一步增加程序控制流的数量,会导致更加频繁的线程切换,其实划分到线程这一层或许就是最好的折中了。

无所不在的线程

使用多线程的场景
     最常见的需要编写多线程程序的场景是:1. 有多个逻辑或者物理的任务需要执行,用多个线程将其区分,而非在一个线程中完成所有工作,在这里使用多线程的主要好处是使程序结构更加清晰、并简化了编程。2. 将一个任务拆分成多个较小的任务,或者将一个任务分为几部分,交给多个线程执行,比如计算任务,此时使用多线程的主要目的就是提升性能了。

需要编写线程安全代码的场景
     除了主动编写多线程程序来"攻",我们还经常需要"防"多线程,防止多线程带来的一些衍生危害。
  • Timer:我们自己写的定时任务,Timer管理的线程会调用。而其他线程也很有可能,因此,在这要注意线程安全。
  • Servlet和JSP:通常我们的Servlet和JSP会被多个线程同时所调用,web服务器会为每一个到来的http请求都从线程池中分配一个线程给它。因此在Servlet和JSP中我们需要保证线程安全,同理,在ServletContext和HttpSession等容器中保存的Servlet过滤器和对象,都必须是线程安全的。
  • 远程方法调用(RMI):在RMI中,存在被多个线程重入的可能,所以必须确保它们自身的线程安全性。


0 0
原创粉丝点击