线程

1、并发和并行

(1)并发:一个时间段有多个程序处于已启动运行到运行完毕之间,同一处理机上进行,会发生抢占,按一定的策略轮流进行。

(2)并行:有多个CPU,一个CPU执行一个进程,另外的CPU执行另一个进程,互补抢占CPU资源,可以同时进行。

2、线程和进程

(1)进程:资源分配的基本单元

==资源分配的基本单元,系统运行程序的基本单位,一个进程内有多个线程。进程是独立的。

(2)线程:CPU调度的基本单元

==执行的基本单元,能独立运行的基本单位,也是独立调度和分派的基本单位

==同一进程的多个线程共享进程的堆和方法区资源。同一进程内的多个线程都具有相同的地址空间(进程的地址空间),同一进程内的线程共享内存和文件,线程间的通信不用调用内核。

==每个线程有自己的程序计数器、虚拟机栈和本地方法栈(私有的)。同一进程间的线程会相互影响。

3、程序计数器(私有)

为了线程切换后能恢复到正确的执行位置。

(1)程序计数器依次读取指令,实现代码的流程控制(顺序执行、选择、循环、异常处理)

(2)多线程下,程序计数器用于记录当前线程执行的位置,从而当线程被切换时能够知道运行的指令的位置

4、虚拟机栈(私有)和本地方法栈(私有)

保证线程中的局部变量不被别的线程访问到

(1)虚拟机栈:执行Java方法(字节码)服务

==每个栈的栈帧用于存储局部变量表、操作数栈、常量池引用等信息。

==方法的调用和执行过程,对应着一个栈帧再虚拟机栈的入栈出栈过程。

(2)本地方法栈:执行native服务

5、堆和方法区(共享公有)

所有线程共享的资源

(1)堆:

==进程中最大的一块内存

==主要用于存放新创建的对象(分配内存)

(2)方法区:

==主要用于存放已被加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据。

6、线程的生命周期和状态

(1)线程的生命周期并不是固定处于某个状态而是随代码的执行在不同状态间切换。

(2)new(创建):新建一个线程对象

(3)runnable(运行):Java线程中将ready(就绪)和running(运行中)称为runnable

== new 状态调用 _Thread.start()_方法后进入ready状态,等待线程调度并分配CPU使用权

== ready状态的线程获得了CPU时间片,开始执行代码,进入running状态

== running状态执行 _Thread.yield()_方法会回到ready状态

(4)blocked(阻塞):表示线程阻塞,没有获得锁的情况下(锁)

(5)waiting(等待):线程执行该对象的 _Object.wait()|Thread.join()_方法,进入waiting状态,需要其它线程进行通知 _Object.notify()|Object.notifyAll()_或中断才能解除该状态

(6)timed_waiting(超时等待):线程执行 Thread.sleep(long mills)| Object.wait(long mills)|Thread.join(long mills)_方法,增加了超时限制,进入timed_waiting状态,超时时间达到后,线程会自动返回 (自动调用Object.notify()|Object.notifyAll())_到runnable状态

(7)terminated(终止):线程执行 _Runnable的run()_方法后,会进入到terminated状态,线程执行完毕

7、sleep()\wait()\yield()\join()\state()\notify()\notifyAll()

(1)Thread.sleep():线程休眠 模拟倒计时、模拟网络延迟

(2)Thread.yield():线程礼让,running回到ready,让cpu重新调度,不一定礼让成功。

(3)Thread.join():线程插队,执行join()方法,原线程进入等待,插入的线程先执行

(4)Thread.state():观测线程转台,执行该方法后能够观测到线程的当前状态

(5)Object.wait():线程等待,进入等待waiting状态

(6)notify():唤醒当前等待线程

(7)notifyAll():唤醒所有等待线程

(8)sleep()和wait()的区别和共同点

==区别:

=====sleep()是Thread类的方法,没有释放锁

通常用于暂停执行

sleep()方法执行完成后,线程会自动苏醒

=====wait()是Object类的方法,会释放锁

通常用于线程间的交互或通信

wait()方法执行后,线程不会自动苏醒,需要别的线程调用同一个对象的notify()或notifyAll()方法。

wait(long timeout),超时后线程会自动苏醒

==共同点:都可以暂停线程的执行

(9)调用start()方法会执行run()方法,不直接调用run()方法?

==调用Thread.start(),自动执行run(),正确的多线程工作

====创建线程时,进入new,调用Thread.start(),会启动一个线程并使线程进入就绪状态,等待调度

====start()执行线程准备工作,会自动执行run()方法

==直接执行run(),不是多线程工作

====相当于直接把run()方法当作一个main()线程下的普通方法进行执行,不会在某个线程中执行它,不是多线程工作

8、线程优先级

(1)JVM采用抢占式调度模型,会给优先级高的线程分配CPU

(2)10个级别的线程优先级(1-10)

(3)当两个线程同时处于ready时,优先级越高越容易被调度

(4)默认优先级是5,Thread.NORM_PRIORITY

(5)最高优先级是10,Thread.MAX_PRIORITY

(6)最低优先级是1,Thread.MIN_PRIORITY

(7)设置优先级方法:Thread.setPriority()

例:Thread.setPriority(Thread.NORM_PRIORITY-1) 4

(8)获取当前的优先级:Thread.getPriority()

例:Thread.getPriority() 4

9、守护线程和用户线程

(1)守护线程Daemon Thread:gc()垃圾回收线程,虚拟机不要等待守护线程执行完毕

=监控内存线程、垃圾回收线程等 “后台线程”

(2)用户线程User Thread:main(),虚拟机必须等待用户线程执行完毕

(3)Thread.setDaemon():默认为false,表示用户线程,正常的线程都是用户线程

10、线程调度

(1)线程调度:给多个线程按照特定的机制分配CPU使用权的过程

==ready状态到running状态,给线程分配CPU的使用权,获得CPU使用权后才会进程running状态

(2)Linux线程调度

==Linux中线程调度是按照进程的调度方式来进行调度的

==调度器是基于线程的调度策略和静态调度优先级来决定哪个线程来运行

==3种调度策略:SCHED_OTHER 分时调度(默认)

SCHED_FIFO 实时调度,先进先出

SCHED_RR 实时调度,时间片轮转

(3)Windows线程调度

==基于优先级的、抢占式调度算法

(4)Java线程调度

==一个Java程序就是一个进程(单进程,多线程的Java)

==Thread类的方法声明为Native的

==JVM实现了一个线程调度器,定义了线程调度模型(协同式线程调度模型、抢占式调度模型)

=====协同式线程调度

1、 线程的执行时间由线程本身来控制,线程工作执行完成后,要主动通知系统切换到另一个线程上

2、好处:实现简单,切换操作对线程可知,没有线程同步问题

=====抢占式线程调度模型

1、多线程系统,每个线程由系统来分配执行时间

2、线程的切换由系统实现

3、优先级高的线程占用CPU,通过线程优先级设置可以设置线程的调度顺序,因为线程调度是取决于原生操作系统,优先级调度可能不太靠谱

11、上下文切换

(1)上下文:线程在执行过程中自己的运行条件和状态

(2)上下文切换:线程切换需要保存当前线程的上下文,等待再次调度时恢复现场,并加载下一个将要占用CPU的上下文的过程。

==让出CPU , 调用sleep()、wait()

==时间片用完

==调用阻塞类型的系统中断,请求IO

==被终止或结束运行

(3)上下文切换是操作系统的基本功能,每次徐娅保存信息、恢复信息,会占用CPU、内存等系统资源进行处理,效率会由损耗,频繁切换会造成整体效率地下。

12、创建线程的方式

(1)继承Thread类创建线程(无法获取执行结果)

继承Thread类并重写run()方法,new创建一个线程对象,调用其start()方法,可以启动一个线程,会运行run()中的代码。

Thread类实现了Runnable接口

(2)实现Runnable接口,可以避免多继承(无法获取执行结果)

实现Runnable接口,重写run()方法,new创建线程对象,调用其start()方法,可以启动线程,运行run()方法中的代码

(3)实现Callable接口

==Callable位于java.util.concurrent包下

==实现Callable接口,重写call()方法(相比run(),call()有返回值)

传入Callable任务给FutureTask对象(FutureTask可用于异步获取执行结果或取消执行任务的场景),FutureTask.get()方法可以异步获取执行结果。(适用于耗时的计算,可以在主线程完成任务后再获取结果,同时,多次调用run()方法,FutureTask只会执行 一次传入的任务)

new创建线程对象,调用其start()方法,可以开启线程

(4)线程池创建线程,直接调用ThreadPoolExecutor

==直接调用ThreadPoolExecutor构造线程

==线程池本身是一个HashSet,多余的任务会放到阻塞队列中。

==线程池创建线程方式很多,可以使用Executor静态工厂构建

但建议使用待遇ThreadFactory参数的ThreadPoolExecutor构造方法设置线程名字。

Original: https://www.cnblogs.com/hexiayuliang666/p/16154777.html
Author: 与长安故里
Title: 线程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/570756/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 值传递和引用传递

    值传递和引用传递 值传递 (pass by value):在调用函数时,将实际参数复制一份传递到函数中,这样在函数中对参数进行修改,就不会影响到原来的实际参数;引用传递 (pass…

    Java 2023年6月6日
    077
  • Aviator和MVEL实现Map过滤(通过动态表达式求值)—Java表达式引擎的使用

    pom com.googlecode.aviator aviator 4.2.10     org.mvel     mvel2     2.4.10.Final View Cod…

    Java 2023年5月29日
    072
  • Effective Java 第三版——78. 同步访问共享的可变数据

    Tips书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code注意,书中的有些代码里方法是基于Java 9…

    Java 2023年5月29日
    084
  • java 程序运行的基础知识【Java bytecode】

    每一个JVM线程来说启动的时候都会创建一个私有的线程栈。一个jvm线程栈用来存储栈帧,jvm线程栈和C语言中的栈很类似,它负责管理局部变量、部分运算结果,同时也参与到函数调用和函数…

    Java 2023年6月15日
    056
  • 哈工大软件构造复习——关于“重载”与“重写”

    防扒链接: 写在前面 在复习软件构造课程的过程中,我对重载(Overload)与重写(Override)产生了不小的疑惑,因其名称的相似性,我时常会混淆二者的概念,因此特写下本篇博…

    Java 2023年6月9日
    078
  • MVCC(多版本并发控制)详解

    在 MySQL InnoDB存储引擎下,RC、RR 基于 MVCC 进行并发事务控制, MVCC 是基于”数据版本”对并发事务进行访问用一个例子来解释一下,…

    Java 2023年6月9日
    067
  • Redis基本操作

    windows 下载 https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100 然后解压 打开服务 然后…

    Java 2023年6月7日
    059
  • javax.servlet.annotation不存在

    我定义了以下一些导入,如下图所示。 我想知道如何消除 “package javax.servlet.<a title=”annotation” href=”https://w…

    Java 2023年5月29日
    058
  • 使用docker部署poetry管理的项目

    前言 poetry是和 virtualenv pipenv一样的包管理工具, 其使用方式类似于 npm我们使用 poetry创建虚拟环境后会生成 poetry.lock和 pypr…

    Java 2023年6月7日
    083
  • 《深入理解Java虚拟机》并发(第12~13章)笔记

    volatile关键字的作用 所有变量的可见性——仅仅是修改后的值的可见性,不保证并发修改时新值和预期一致。即只保证读,不保证写。 禁止指令重排序——修饰的变量,读写不会指令重排。…

    Java 2023年5月29日
    063
  • 朱晔和你聊Spring系列S1E8:凑活着用的Spring Cloud(含一个实际业务贯穿所有组件的完整例子)

    本文会以一个简单而完整的业务来阐述Spring Cloud Finchley.RELEASE版本常用组件的使用。如下图所示,本文会覆盖的组件有: Spring Cloud Netf…

    Java 2023年5月30日
    084
  • 程序员如何利用技术能力变现

    本文节选左耳朵耗子相关文章,与读者共勉! 本质上来说,程序员是手艺人,有手艺的人就能做出别人做不出来的东西,而付费也是一件很自然的事了。那么,这个问题就成了,如何让自己的&#822…

    Java 2023年6月6日
    083
  • java入门

    1.基础语法 基本数据类型 整数类型 浮点类型 字符类型 布尔类型 类型转换 运算符 算术运算符 关系运算符 逻辑运算符 赋值运算符 三元运算符 字符串运算符 位运算符 分支 if…

    Java 2023年6月5日
    072
  • MyBatis复杂映射开发之一对一查询

    一对一查询需求 用户表和订单表的关系为:一个用户可以有多个订单,一个订单只能从属于一个用户 一对一查询需求:查询一个订单,同时查询出该订单所对应的用户 对应的sql语句: sele…

    Java 2023年6月5日
    0113
  • Java基础随笔2

    ++:自增 –:自减 单独使用的时候,++或者–无论是放在变量的前面还是后面,结果是一样的。 参与操作的时候: 如果++或者–在变量的后面,先拿…

    Java 2023年6月5日
    071
  • String、StringBuilder和StringBuffer

    JVM(Java虚拟机) 学习String类前,先了解一下JVM,也称为Java虚拟机。 JVM内存分有几大区域,其中,常见有堆、桟、方法区、常量池。 堆是运行时数据区,类通过ne…

    Java 2023年6月5日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球