zoukankan      html  css  js  c++  java
  • 并发编程学习(1)----并发编程基础

    前言:多线程是程序员必须掌握的一项基础知识,但是由于各种框架封装使得我们平时很少能接触到多线程。一旦项目中发生问题,便无从下手。学会了多线程不仅能帮助你更好地处理项目中的问题,还能对你理解一些框架有所帮助。本系列以《Java并发编程的艺术》为参考,结合网上的一些资料并结合自己的理解整理而成。如有错误,欢迎指正。 

    1、几个概念

    1)进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的独立单位。一个操作系统中可以同时运行多个任务(程序),每个运行的任务(程序)被称为一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。

    2)线程:它是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可以与其它同属一个进程的其他线程共享进程所拥有的全部资源。

    3)上线文切换:

      即使单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的。

      CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

      这就好比我们同时读两本书,当在读一本英文的技术书时,发现某个单词不认识,于是便打开字典查找,但是查找之前必须先记住这本书已经读到了多少页的多少行。等查完单词以后,能够继续读这本书。这样的切换是会影响读书效率的,同样上下文切换也会影响多线程的执行效率。

    2.为什么要使用多线程?

    1)充分利用系统资源

      由于摩尔定律周期越来越长,处理器性能的提升方式也从更高的主频向多核发展。线程是大多数操作系统调度的基本单元,而线程是进程的一个实体。一个线程同一时刻只能运行在一个cpu上,这样就无法充分利用系统资源。如果将计算任务分配给多个处理器核上,就会显著减少程序的处理时间。

    2)更快地响应时间

      例如,在一些复杂的业务中,用户从点击按钮开始,服务端需要进行一系列处理过程才能将最终的结果返回给客户端。使用多线程技术,可以将实时性要求高的数据处理完成以后即将执行结果返回到客户端。而一些数据一致性不强的操作派发给其它线程处理(如消息队列/Worker)。这样可以缩短响应时间,提升了用户体验。

    3)更好的编程模型

      Java为多线程提供了良好的、考究并且一致的编程模型,使得开发人员更加专注于问题的解决。某些类型的问题,例如仿真,没有并发是很难解决的。大多数人都看到过至少一种形式的仿真,例如计算机游戏中或电影中计算机生成的动画。完整的仿真通常涉及许多交互式元素,每一个都有自己的“想法”。从编程角度看,模拟每个仿真元素都是独立的任务----比如游戏中的门与岩石,或者精灵与巫师。(详细可参考Tink in Java第四版 21.1.2小节)

    3.多线程面临的问题

      在并发编程中,需要解决的两个问题:线程之间如何通信以及线程之间如何同步。通信是指线程之间以何种机制来交换信息,同步是指程序中用于控制不同线程间相对执行顺序的机制。

    1)线程间的通信机制有两种:共享内存和消息传递。

      共享内存的并发模型中,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。在消息传递的并发模型里,线程之间没有公共状态,线程间的通信必须通过发送消息来进行显示通信(比如Java中Object对象的wait()与notify())。

    2)同步机制

      在并发编程中,尤其是在处理共享资源时,需要将某些操作(例如写操作)转化为同步,以免造成难以想象的后果。常见的同步机制有以下两种:JVM层面,借助Object的monitor实现(synchronized);通过总线锁或者锁定内存部分区域实现,例如volatile。

    4、并发编程挑战

    1)上下文切换。

      当线程较多时,频繁的上线文切换会导致执行效率降低,合理地调整线程数可以将并发执行效率最大化。

    2)死锁。

      锁是非常有用的工具,运用场景非常多。但是如果使用不当可能会带来死锁问题,严重时可能使系统瘫痪。死锁即创建两个线程A和B,A拥有锁a,同时需要获取锁b,而B拥有锁b,同时需要获取锁a。两者均持有锁,无法获取所需锁。在实际开发中,要避免死锁的产生。

      避免死锁的常见方法

      a.避免一个线程同时获取多个锁

      b.便面一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。

      c.尝试使用定时锁,使用lock.tryLock(timeout)

           d.对程序进行异常处理,保证程序发生异常时锁可以正常释放。

           d.对于数据库锁,加锁和解锁必须在同一个数据库连接里,否则会出现解锁失败问题。

    3)资源限制。

      资源限制指在并发编程中,受限于计算机硬件资源或软件资源。例如,一个服务器的贷款只有2M/s,当使用多线程时,并不会提高下载速度。因为受限于资源,线程仍然是串行执行。程序反而会更慢,由于上下文切换和资源调度时间。

      对于硬件资源,可以通过增加带宽或者增加集群方式解决。对于软件资源,例如数据库连接,可以通过控制线程并发数来使得资源利用率最大化。

      

      

  • 相关阅读:
    typescript 装饰器
    typescript 中的模块
    深入理解typeScript中的泛型类
    泛型 泛型类
    vue跨域
    我喜欢的网站
    vuex
    路由导航守卫
    最多显示两行
    git命令
  • 原文地址:https://www.cnblogs.com/han02216/p/6678152.html
Copyright © 2011-2022 走看看