多线程01(一)

简介: 多线程01

一、相关概念

1.1程序.

  • 程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象(下载的软件里面的各种系统文件)。
  • 1.2进程.
  • 进程(process):
  • 程序的一次执行过程,或是正在内存中运行的应用程序。如:运行的Eclipse、QQ音乐等。
  • 每个进程都有一个独立的内存空间,系统运行一个程序即是一个进程从创建、运行到消亡的过程(生命周期)。
  • 进程到运行不仅仅需要CPU,还需要很多其它资源,比如:内存、显卡、磁盘等。
  • 程序是静态的,进程是动态的。
  • 进程是操作系统调度和分配资源的最小单位(亦是系统运行程序的基本单位。一定要和线程区分开),系统在运行时会为每个进程分配不同的内存区域和时间片。操作系统调度器:拆分CPU为一段段时间片的运行片,轮流分配给不同的程序。
  • 现代的操作系统,大都是支持多进程的,支持同时运行多个程序。比如:一边打游戏,一边使用QQ聊天,一边使用录屏软件,同时还开着画图板,dos窗口等软件。
  • 不同进程之间是不共享运行时内存的,但是进程和进程之间是可以进行数据交互和通信,成本很高。如:在京东里面通过微信付款、在淘宝里面通过支付宝付款。
  • 1.3线程.
  • 线程(thread):
  • 进程可进一步细化为线程,是程序内部的一条执行路径。一个进程中至少有一个线程。
  • 一个进程同一时间若并行执行多个线程,就是支持多线程的。

  • 线程作为CPU调度和分配的最小单位(一定要和进程区分开)。有句话说CPU只能看到线程,可以这么理解,假设我是CPU,我闭着眼,操作系统调度器将一个进程分配给我之后,我拿到进程睁开眼,我看到的是什么?我看到的是进程中的很多线程,那么我现在能调度和分配的是什么?进程?不行,因为我看不到其他进程,何来调度分配,只能调度我看到的那些线程,如果我是4核的话,把线程ABCD分配到核心1234,其他的线程依然要等待分配,至于等待多久,如何分配,暂不在本文讨论范围。于是线程是CPU调度和分配的基本单位。
  • 一个进程中的多个线程共享相同的内存单元,它们从同一个堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患。
  • 下图中,红框的蓝色区域为线程独享,黄色区域为线程共享。

  • 1.4查看进程和线程.
  • 电脑底部任务栏,右键----->打开任务管理器,可以查看当前任务的进程。
  • 1. 每个运行的应用程序都是一个进程:

    2. 一个应用程序的多次运行,就是多个进程:
    3. 一个进程中包含多个线程:

  • 1.5线程调度.
  • 分时调度:所有线程轮流使用 CPU 的使用权,并且平均分配每个线程占用 CPU 的时间。
  • 抢占式调度:让优先级高的线程以较大的概率优先使用 CPU。如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

  • 1.6多线程程序的优点.
  • 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
  • 提高计算机系统CPU的利用率。
  • 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。

  • 1.7单核CPU和多核CPU.
  • 单核CPU,在一个时间单元内,只能执行一个线程的任务。例如,可以把CPU看成是医院的医生诊室,在一定时间内只能给一个病人诊断治疗。所以单核CPU就是,代码经过前面一系列的前导操作(类似于医院挂号,比如有10个窗口挂号),然后到cpu处执行时发现,就只有一个CPU(对应一个医生),大家排队执行。这时候想要提升系统性能,只有两个办法,要么提升CPU性能(让医生看病快点),要么多加几个CPU(多整几个医生),即为多核的CPU。
  • 问题:多核的效率是单核的倍数吗?譬如4核A53的cpu,性能是单核A53的4倍吗?理论上是,但是实际不可能,至少有两方面的损耗。
  1. 一个是多个核心的其他共用资源限制。譬如,4核CPU对应的内存、cache、寄存器并没有同步扩充4倍。这就好像医院一样,1个医生换4个医生,但是做B超检查的还是一台机器,性能瓶颈就从医生转到B超检查了。
  2. 另一个是多核CPU之间的协调管理损耗。譬如多个核心同时运行两个相关的任务,需要考虑任务同步,这也需要消耗额外性能。好比公司工作,一个人的时候至少不用开会浪费时间,自己跟自己商量就行了。两个人就要开会同步工作,协调分配,所以工作效率绝对不可能达到2倍。

  • 1.8并行与并发.
    1.8.1并行.
  • 并行(parallel):指两个或多个事件在同一时刻发生(同时发生)。指在同一时刻,有多条指令在多个CPU上同时执行。比如:多个人同时做不同的事。
  • 比如,A、B、C三个指令同时执行:

  • 1.8.2并发.
  • 并发(concurrency):只是一种现象,指两个或多个事件在同一个时间段内发生。即在一段时间内,有多条指令在单个CPU上快速轮换、交替执行,使得在宏观上具有多个进程同时执行的效果。
  • 比如,A、B、C三个指令在同一时间段内快速切换执行:

  • 解释一:
    多线程并发只是表面和感觉上的并发,并不是实质上的并发。一个线程要运行,它必须占有CPU,而我们目前用的计算机大多都是单CPU的,所以一次最多只能有一个线程获取CPU并运行。
    多线程的实质是“最大限度地利用CPU资源”,当某一个线程的处理不需要占用CPU而只需要和I/O等资源打交道时,让其他线程有机会获得CPU资源。这有点类似于“统筹方法”,例如让你打扫房子和烧水,要在最短的时间内做好这两件事,你一定会想到先把水烧上,然后在等水烧开的空闲时间中去打扫房子,而不是先打扫好了再去烧水,也不是先烧好了再去打扫,这个例子里面,你是那个唯一的CPU,而烧水和打扫就是两个线程。
    虽然CPU只有一个,但是它在多个线程之间频繁切换,当切换的频率高到一定程度时,我们就感觉所有的线程在同时运行,于是感觉这多个线程是并发的。因此,并发并不是真的指多个线程同时运行,它仅仅只是形容一种现象。
    解释二:
    在操作系统中,启动了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单核 CPU 系统中,每一时刻只能有一个程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。宏观并行,微观其实是串行(排队)。 而在多核 CPU 系统中,则这些可以并发执行的程序便可以分配到多个CPU上,实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序,这样多个程序才可以真正的同时执行。目前电脑市场上说的多核 CPU,便是多核处理器,核越多,并行处理的程序越多,能大大的提高电脑运行的效率。

  • 1.8.3总结.
  • 并发只是一种程序在运行时的现象效果(宏观并行,微观串行),和串行、并行没有可比性。串行即排队,并行才是真正的多个程序同时执行。
  • 单CPU中进程只能是并发,多CPU计算机中进程可以并行也可以并发。
  • 单CPU单核中线程只能并发,单CPU多核中线程可以并行也可以并发。
  • 无论是并发还是并行,使用者来看,看到的是多进程,多线程。

  • 1.9线程分类.
  • JAVA中的线程主要分为两类:用户线程(User Thread)和守护线程(Daemon Thread)。
  1. 用户线程:AVA语言中无论是线程还是线程池,默认都是用户线程,用户线程也被称为普通线程。
  • main线程也是用户线程,又叫主线程,是由JVM创建的。
  • 用户线程创建的子线程默认是用户线程,可以设置为守护线程:setDaemon(true)。比如在main()方法(主线程)里面创建的线程就是子线程。
  1. 守护线程:也被称之为后台线程、服务线程或精灵线程。
  • 守护线程是为用户线程服务的,当线程中的用户线程都执行结束后,守护线程也会跟随结束。
  • 守护线程具有自动结束生命周期的特性,而非守护线程则不具备该特性。
  • 守护线程的优先级和用户线程优先级一致;
  • 守护线程的子线程也是守护线程。
  • 垃圾回收线程就是典型的守护线程,随主线程结束而结束。
  • 设置用户线程为守护线程方法:setDaemon(true) ,该方法必须在 start()方法之前设置, 如果设置在 start() 之后,程序执行会报错,守护线程也不会生效。
  • 判断线程是否是守护线程方法:isDaemon();
  • JVM必须确保所有的用户线程执行结束之后才能退出;如果只还有守护线程在运行,JVM不用等待守护线程执行结束,会直接退出。验证代码如下:

二、创建线程的方式.

2.1概述.

  • Java语言的JVM允许程序运行多个线程,使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例。
  • Thread类的特性:
  • 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,因此把run()方法体称为线程执行体。
  • 通过该Thread对象的start()方法来启动这个线程,而非直接调用run(),要想实现多线程,必须在主线程中创建新的线程对象。

2.2创建线程的几种方式.

  1. 继承Thread类;
  2. 实现Runnable接口;
  3. 实现Callable接口(JDK1.5出现的);
  4. 使用线程池(JDK1.5出现的)。

3.继承Thread类方式.

3.1使用步骤.

  • 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务;
  • 创建Thread子类的实例,即创建了线程对象;
  • 调用线程对象的start()方法来启动该线程。

3.2代码演示.

  • 创建 Thread类的子类:

  • 测试类:

  • 线程运行效果图:




相关文章
|
6月前
|
并行计算 调度 UED
为什么要用多线程?
为什么要用多线程?
70 0
|
Java API 调度
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
22天前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
6月前
|
Java 调度
多线程问题(一)
多线程问题(一)
42 0
|
6月前
|
Java API 调度
多线程知识篇
多线程知识篇
|
安全 Java 调度
多线程
线程是进程中执行运算的最小单位,是进程内部的一个执行单元 1、多个线程同时进行,采用枪占的机制,单核计算机一个时间只有一个线程执行,采用枪占资源的方式
60 0