当前位置: 首页 > news >正文

java多线程(一)-概述

最近这段在看java多线程编程方面的东西。所以特写了几篇文章,来总结和回顾一下自己所学习到的相关知识。因为水平有限,文章中总结不全面甚至理解错误的地方,欢迎读者指点批评。

我们平时所接触到的程序,都是顺序编程。
顺序编程的意思是,程序中的所有事物在任意时刻都只能执行一个步骤(包括那些代码当中的顺序结构,选择结构,循环结构),
顺序编程满足了我们能够碰到的大部分问题,但是有些问题,仅仅依靠顺序编程是不够的,举个例子,一个带界面的音乐播放程序,在播放歌曲的同时也能及时的响应用户在界面上进行的的按键操作(比如点击 下一曲 按钮)。那么此时顺序编程就不合适了,因为这是需要两件同时执行的事情,如果采用顺序编程,为了及时响应按键操作,我们需要在代码的很多地方都要加上检测按键状态的代码。而这种场景下就需要并发编程了。

并发编程 有不同的实现方式。 比如 多进程模式,多线程模式等。
而最常见也最直接的就是 操作系统级别使用的进程,所谓 进程就是运行在它自己的地址空间内的自包容的程序。比如,可以在电脑上,同时并行进行几个不同的任务,qq和人聊天,酷狗播放器播放音乐,然后浏览器下着文件,这就是三个不同的进程,这三个进程彼此之间相互隔绝,不受其他进程影响。

而对于同一个进程,也可以采用多线程开发技术,使得一个程序内部多个线程可以并行运行。

当然,对于单核cpu,我们说计算机能在同一个时间点并行运行多进程或多线程。它们实际上都不是真正意义上的同一个时间点,只不过cpu切换速度极快,操作系统将cpu时间切片,分配给不同的任务。虽然看起来每个任务在执行过程中都是有时运行有时停止,但是鉴于cpu执行的速度极高,所以在我们使用者看来,那都是连续的,不间断的。这几个不同的任务就像同时并行运行一样。

而伴随着多核cpu的出现,几个核同时运行,这个时候,它们才有可能是在真正的同一个时间点并行运行。


而多线程,因为会对相同的内存空间进行并发读写操作,所以它们更加复杂。
解释一下这句话,还是 回到刚才举的那个例子,在一台电脑上,同时运行几个不同的任务。qq和人聊天,酷狗播放器播放音乐,然后浏览器下着文件。我们知道,无论什么程序,归根结底编译到了最底层,那就是0和1。因为cpu只认识0和1,如果把0和1转化为容易阅读的语言,那就是汇编语言。看过汇编的应该知道,类似 什么mov ax,bx 之类的语句都是直接操作寄存器或内存地址的。那么这个时候问题就来了,酷狗播放器,qq,浏览器这三个程序,编译到了汇编层次,那么也会直接操作寄存器和内存地址,那么为什么他们这些程序之间不冲突呢?原因就是因为 其实他们这个地址之类的,都是虚拟内存地址。酷狗播放器和qq编译成汇编语言之后,他们的内存地址都是虚拟的,所以哪怕这两个程序在汇编层面都操作同一个内存地址,也不会彼此冲突。这中间的功劳就是属于操作系统和cpu。操作系统在运行这两个进程时,会和cpu一起起作用,把他们的虚拟地址空间转换为实际的地址空间。其实说白了,就是 酷狗播放器,qq,浏览器在编写他们各自的代码的时候。根本不会考虑汇编层面上,寄存器,内存地址之类的问题。他们只需要写好自己程序本身的代码就行了。至于那些多个进程怎么运行之类的复杂问题的,上层开发的程序员们是不用关心的。

而多线程,他们归根到底还是属于同一个进程,因此多个不同线程还是对于同一内存空间进行操作,所以多线程更复杂,更容易出问题。

对于多进程,某个进程崩溃了,那么对其他进程 没啥影响,但是对于多线程,某个线程崩溃了,它所属的这个进程也会受到直接影响。

当然,我们在说不同的进程在运行的时候,都属于各自干好自己的事情,中间不会发生什么联系。这样就避免了相互干扰。不过操作系统当然也提供了进程间通信机制(IPC),比如linux的 管道,信号,套接字之类的。

 

而从表面上看,如果同样一个任务(进程),分解成多个线程来执行,和单独一个线程来执行,理论上前者的开销应该是更大的,原因很简单,执行多线程会增加 上下文切换的代价。但是实际上,多线程之所以更快,有两个主要因素。
(1)阻塞。程序因为程序控制之外的某些因素(比如I/0)而导致不能继续执行,cpu是如此宝贵的资源,如果cpu一直处于等待状态,那岂不是一种很大的浪费。拿i/o操作来说,cpu的执行速度极高,它的时间都是按照纳秒为单位的,但是执行程序所需要的资源或数据确往往在内存,硬盘,乃至网络服务器上,它们的速度相对于cpu那就太慢,甚至极慢。如果是顺序编程,在这种情况下,cpu只能干等着,没办法继续干活。那么这种情况下,多线程就变的很有必要了。此时cpu可以切换执行另一个任务,那么就不用干等着其中一个线程。

(2)多核cpu的出现,在最初的时候cpu都是单核的,但是到现在四核八核都很普遍的情况下,如果是顺序编程只能在某一个核上运行。找人完成一件任务,一个人单独干,和8个人协助干,虽然后者会需要花费更多的组织和协调的耗费,但是明显后者干活比前者快。

多线程编程将一个大的程序(任务/进程)划分为多个分离的,独立运行的线程(子任务),一个线程就是该进程中的 一个单一的顺序控制流,每个线程虽然没有独立的地址空间(因为只有进程才有),但是各个线程有自己的堆栈和局部变量。而在线程本身来看,就像它单独占有cpu一样。虽然底层机制是操作系统切分了cpu的时间,给它分配了这一段的时间。不过上层开发的程序员是不用关心这些的,所以这种线程模型方便了上层开发者。

 

-------
作者: www.yaoxiaowen.com
github: https://github.com/yaowen369

相关文章:

  • 网络安全的起跑点Trusted Computing
  • 利用反射——动态调用类中的方法
  • grep过滤用法介绍(二)
  • SourceForge.net 出问题了?
  • 二、中断线程
  • 看看近期读者的书评
  • 程序员需要的都在这里了
  • 浅谈我的销售体会(二)
  • Python正则表达式
  • 桃花庵
  • SwitchyOmega 设置修改代理
  • 【美食】去掉美女脸上斑点的八种饮食疗法
  • Android混淆打包
  • Ajax中动态执行返回到innerHTML中的js
  • css深入理解relative
  • Babel配置的不完全指南
  • CentOS6 编译安装 redis-3.2.3
  • eclipse(luna)创建web工程
  • golang中接口赋值与方法集
  • Gradle 5.0 正式版发布
  • Java应用性能调优
  • JWT究竟是什么呢?
  • python 学习笔记 - Queue Pipes,进程间通讯
  • QQ浏览器x5内核的兼容性问题
  • Shell编程
  • SpringBoot几种定时任务的实现方式
  • 分享一份非常强势的Android面试题
  • 复习Javascript专题(四):js中的深浅拷贝
  • ------- 计算机网络基础
  • 京东美团研发面经
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 数据结构java版之冒泡排序及优化
  • 与 ConTeXt MkIV 官方文档的接驳
  • 1.Ext JS 建立web开发工程
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​【已解决】npm install​卡主不动的情况
  • ​业务双活的数据切换思路设计(下)
  • ​用户画像从0到100的构建思路
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (生成器)yield与(迭代器)generator
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .naturalWidth 和naturalHeight属性,
  • .net refrector
  • .Net 垃圾回收机制原理(二)
  • .net流程开发平台的一些难点(1)
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • [100天算法】-实现 strStr()(day 52)
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——
  • [ASP.NET MVC]如何定制Numeric属性/字段验证消息
  • [C#]C# winform部署yolov8目标检测的openvino模型
  • [c++] 什么是平凡类型,标准布局类型,POD类型,聚合体
  • [CISCN2019 华北赛区 Day1 Web2]ikun
  • [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape