最近这段在看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

java多线程(一)-概述的更多相关文章

  1. Java多线程——<一>概述、定义任务

    一.概述 为什么使用线程?从c开始,任何一门高级语言的默认执行顺序是“按照编写的代码的顺序执行”,日常开发过程中写的业务逻辑,但凡不涉及并发的,都是让一个任务顺序执行以确保得到想要的结果.但是,当你的 ...

  2. Java 多线程 - 总结概述

    概述 菜鸟教程: Java 给多线程编程提供了内置的支持. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程 ...

  3. java多线程基本概述(一)——线程的基本认知

    1.1.概念: 进程:进程是操作系统结构的基础,是一次程序的执行:是一个程序及其数据再处理器上顺序执行时所发生的活动:是程序再一个数据集合上运行的过程,它是系统进行系统资源分配和调度的最小单元. 线程 ...

  4. java多线程基本概述(四)——死锁

    package mytask; public class Task { public static void main(String[] args) { DeadThread thread = new ...

  5. java多线程基本概述(三)——同步方法

    非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的.而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象. 1.1 ...

  6. java多线程基本概述(二)——Thread的一些方法

    在Thread类中有很多方法值得我们关注一下.下面选取几个进行范例: 1.1.isAlive()方法 java api 描述如下: public final boolean isAlive() Tes ...

  7. java多线程基本概述(五)——线程通信

    线程之间的通信可以通过共享内存变量的方式进行相互通信,也可以使用api提供的wait(),notify()实现线程之间的通信.wait()方法是Object类的方法,改方法用来将当前的线程置入&quo ...

  8. java多线程基本概述(七)——join()方法

    在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用join()方法.调用join()方法的意思是当前线程 ...

  9. java多线程基本概述(十三)——Executor

    1:Executor接口 public interface Executor 执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等 ...

  10. java多线程基本概述(二十)——中断

    线程中断我们已经直到可以使用 interrupt() 方法,但是你必须要持有 Thread 对象,但是新的并发库中似乎在避免直接对 Thread 对象的直接操作,尽量使用 Executor 来执行所有 ...

随机推荐

  1. 企业级LNMP架构搭建实例(基于Centos6.x)

    1.1 部署LNMP架构说明 1.1.1 LNMP架构内容 01.部署linux系统 02.部署nginx网站服务 03.部署mysql数据库服务 04.部署php动态解析服务 1.1.2 配置LNM ...

  2. SQL图像查看器 —— SQL Image Viewer

    有时候往数据库里面存储了一些图片,但是如果不写读取程序的话,就不知道存储的对不对. 或者查看SQL数据库里面二进制看不懂,这个看图片很直观的. 就需要SQL Image Viewer这么一个

  3. 基于maven的ssm框架整合

    基于maven的ssm框架整合 第一步:通过maven建立一个web项目.                第二步:pom文件导入jar包                              (1 ...

  4. tf.train.ExponentialMovingAverage

    这个函数可以参考吴恩达deeplearning.ai中的指数加权平均. 和指数加权平均不一样的是,tensorflow中提供的这个函数,能够让decay_rate随着step的变化而变化.(在训练初期 ...

  5. mac cocos2dx android

    1. localhost:proj.android mxhd4$ ./build_native.sh 报错 Compile++ thumb  : cocosdenshion_static <= ...

  6. Java加载资源文件的两种方法

    处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都需要与配置文件打交道.Java将配置文件当作一种资源(resource)来处理,并且提供了两 ...

  7. 自学Zabbix1.3-zabbix进程

    默认情况下zabbix包含5个程序:zabbix_agentd.zabbix_get.zabbix_proxy.zabbix_sender.zabbix_server,另外一个zabbix_java_ ...

  8. 用IFeatureWorkspaceAnno.CreateAnnotationClass 创建注记图层时报“The application is not licensed to modify or create schema”的错误的解决方案。

    用IFeatureWorkspaceAnno.CreateAnnotationClass 的方法创建注记图层的时候报"The application is not licensed to m ...

  9. spark-submit参数说明--standalone

    示例: spark-submit [--option value] <application jar> [application arguments] 参数名称 含义 --master M ...

  10. 小白的Python之路 day1 表达式if ... else ,while循环,for循环

    表达式if ... else 一.用户登陆验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 提示输入用户名和密码    # 验 ...