java自学之路-day17

     2022-03-21     656

关键词:

JAVA17

多线程

进程和线程的概念

进程

l  正在运行中的程序

l  程序存储在硬盘中 当进入内存运行时

l  内存中的每一个程序就叫进程

l  并且每一个进程都有一个独立的功能

线程

l  迅雷中的多线程下载

l  main方法中有很多方法一次排列

  1. 如果其中一个方法执行了很多次循环
  2. 那么下一个方法就不会执行
  3. 从入口main到结束,一条路走到底 必须一个一个的执行
  4. 这种程序是单线程程序
  5. 效率慢

 

l  例如

多台电脑网吧上网

多条路通行

线程

概念

l  CPU 中央处理器 inter AWD

l  四核心 八线程

l  360杀毒工具

  1. 进入内存
  2. 有一个进程 360safe.exe
  3. 所有功能进入内存
  4. 所有功能都是程序中的一个方法
  5. 所有功能可以单独同时运行
  6. 所有功能由CPU运行
  7. 每开启一个功能 cpu就会开启新的执行路径
  8. 也就是一个新的线程
  9. 早期cpu一次只能执行一个线程 时间片轮回切换运行
  10. 当前cpu有多核心 那么同一时刻就能执行多个线程
  11.  

 

迅雷下载

l  多线程下载

l  并不是提高了网速 而是多线程提高了速度

 

线程的运行模式

分时调度

l  所有线程轮流使用cpu资源 平均分配对个线程占用CPU时间

抢占式调度

l  优先级高的多使用cpu资源 优先级相同的随机选择一个进行调度

l   

 

main主线程

l  编译

l  JVM运行main方法

l  找操作系统 开线程

l  对于cpu有了一个执行的路径 运行方法main路径有个名字main

l  这个就是主线程

 

 

l  多线程就算一条线程出现错误 其他线程也会执行

Thread类

概述

l  Java.lang包中

l  Jvm允许程序运行多个线程

l  每一个线程都有一个优先级

l  创建线程有两个方法

  1. 继承Thread类 重写run方法
  2. 实现Runable接口 实现run方法

实现线程继承Thread

l  定义一个类继承Thread 重写run方法

 

l  在测试类中实例化这个类的对象 调用start方法

 

 

l  Start方法只能执行一次

l  执行顺序跟之前不一样

l  图解

  1. Jvm开启main主线程
  2. cpu运行主线程
  3. 运行中 方法中开了一个新线程
  4. Cpu执行新线程
  5. 继续执行start方法启动新线程 准备执行run方法
  6. cpu有了两个执行路径
  7. cpu自己控制运行main方法的循环还是run方法的循环
  8. cpu分配时间片给线程

 

为什么要继承Thread

l  调用run和start区别

  1. Start开启线程 并让jvm调用run方法在开启的线程中运行
  2. run就是一个方法而已 等待被执行 没有其他功能

l  Thread是线程类 继承这个类就是 线程类

l  直接创建Thread类对象,run方法是这个类的方法,没有任何操作 不能运行自定义的代码 所以需要继承这个类 重写run方法然后执行我们需要在另一个线程中执行的代码

l  Run方法的作用是为了执行我们要在新线程中执行的代码

线程运行的内存图

l  Main方法先进入

l  然后调用start方法 run方法准备被jvm调用

l  Run方法不进入这个栈 会新开一个栈空间单独执行run方法

l   

 

获取线程名称

l  main主线程名称就是 main

l  控制台获取默认线程名字

 

l  getName获取线程名

 

调用父类方法可以不写super

l  获取main线程名字

Static Thread currentThread();

获取正在运行本方法的线程名字 返回Thread类型

 

简化

 

设置线程名称

l  setName() 

  1. 需要在主线程中改名
  2. main线程名改不了

 

l  构造方法改线程名

  1. 父类中有一个构造方法可以改名称

 

  1.  

 

Sleep方法

l  线程停止特定时间

 

 

 

l  抛异常

因为休眠过程中被唤醒会抛此异常

 Runnable接口

l  实现线程的的另一种方式

l  实现接口Runnable

l  实现方法run

示例

  1. 先创建接口实现类
  2. 然后创建Thread对象 传递实现类对象
  3. 然后调用start方法

原理

 

  1. Thread有一个构造器方法 可以传入Runnable类型对象
  2. 定义一个类实现Runable接口 新建对象传入Thread的构造方法中就可以开启一个新线程运行代码
  3. 避免了单继承局限性
  4. 线程分为了两个部分 一部分是线程对象 一部分是线程任务
  5. 从而降低了耦合度
  6.  

好处

 

匿名内部类实现线程程序

l  前提 继承或接口实现

l  new 父类或者接口实现(){   重写抽象方法     }

l  示例

  1. 继承Thread

 

  1.  实现接口

 

线程的状态图

l  NEW   新建状态 

 

l  RUNNABLE   运行状态 正在JVM虚拟机中执行此线程

 

l  BLOCKED   受阻塞

死锁 CPU资源被抢走

 

 

l  WAITTING        等待 无限休眠

  Object类中的方法

 

l  TIMED_ WAITTING   休眠

 

l  TREMINATED 死亡状态

 

l  受阻塞具有cpu的执行资格 等待CPU的资源

l  休眠等待 线程放弃CPU的执行资格

线程池

概述

l  是一个容器可以存放多个线程

l  程序一开始的时候 创建多个线程 存放到集合中

l  使用时 用remove方法取出线程 使用完毕 再用add重新添加进去

l  之前都是自己开发线程池

l  Jdk1.5之后添加了线程池技术

使用

使用线程池方式 Runable接口

l  由线程池工厂创建

l  再调用线程池中的方法创建线程

l  Executors类

  1. Java.util.concurrent包
  2. 方法

a)         创建多个

 

b)         创建单个

 

c)         返回值是线程池类对象

 

  1. 示例

 

 

控制台没停止 线程用完后有回到了线程池

线程名字

 

停止线程

Shutdown 线程停止

实现线程Callable方法

l  Runnable接口 线程运行完没有结果 不能抛异常

l  Jdk1.5后有个Callable接口 call方法 等同于run

l  call方法有返回值 可以抛异常 

l  先用工厂类静态方法newFixedRhreadPool创建线程池对象

l  线程对象 调用方法submit提交线程任务 传入一个Callable接口实现类

l  示例

 

 

父类接口抛了异常 子类可抛异常也可不抛异常

练习

l  异步计算

线程操作共享数据的安全问题

售票示例

l  多个线程同时运行 同时运行某段代码

l  每次运行结果和单线程运行结果一样

l  售票

l  多种方式购票 多个线程操作同一个数据

l  此时应该数据同时更新 否则会出现安全问题

l  示例

 

 

 

数据正常 但是存在安全隐患

安全问题引发

l  T0判断完毕 准备开始操作

l  此时cpu被t1线程抢占

l  T1判断完毕 准备进行操作

l  此时被t2线程抢占

l  T2判断完毕 准备进行操作

l  此时cpu资源获得 t0执行操作 – 数据为0

l  T1也执行—数据为-1

l  T2也执行--数据为-2

l  此时出现了线程安全问题

l  模拟示例

  1. 执行前停顿一下 sleep
  2.  

 

解决

  1. 同步代码块
  2. 当一个线程进入数据操作是无论是否休眠 其他线程只能等待
  3. Sun公司提供了一个技术实现了这样的解决
  4. 公式

Synchronzied(任意对象){

   线程操作的共享数据

}

  1. 同步代码块
  2. 示例

 

不能写匿名对象

 

变得安全了

 

但是速度变慢了

执行原理

l  同步对象 任意对象

l  对象 :同步锁 对象监视器

l  同步保证安全性 没有锁的线程不能执行 只能等

l  线程遇到同步代码块后 判断同步锁还有没有

l  如果没有就等待

l  如果有 获取锁  将同步锁设为0

l  进入同步代码块 此时如果休眠了

l  另一个线程过来 要执行代码 会判断同步锁是否有 此时显然是没有的 因此就进不去代码块 不能执行代码

l  此时如果第一个线程 唤醒了 就继续执行代码  然后释放同步锁

l  因此一个线程需要判断锁 获取锁 释放锁 所以就延长了很长时间

 

l  同步锁原理和上厕所

  1. 对象就是厕所的门
  2. 同步锁就是厕所门的锁

l  多个线程访问一个共享数据就要设置同步锁

同步方法

l  代码简洁

l  将线程共享数据和同步抽取到一个方法中

 

l  方法的声明加上同步关键字 然后把同步不代码块删除

 

l  StringBuffer 就有这种同步方法 跑的慢

 

l  StringBuilder 是线程不安全 跑的快

 

l  同步方法有锁吗?

  1. 肯定有
  2. 对象锁是本类的对象引用 this

 

l  如果方法是静态的

  1. 静态方法中的锁不是this本类对象引用
  2. 静态不属于对象引用
  3. 静态方法中对象锁是 本类类名.class

 

 

  1. 涉及到反射的原理

JDK1.5新特新 Lock接口

l  释放同步锁 看不到

l  如果代码出现异常 锁就不会释放

l  因此JDK1.5后出现了Lock接口

l  此接口提供了比使用synchornized更多的方法和语句可获得的跟广泛的锁定操作

l  示例

  1. 接口方法

lock 获取锁

unlock 释放锁

  1. 实现类

ReentrantLock

  1. 在成员变量 通过实现类创建lock接口的实现类对象
  2. 在要锁的代码前 调用lock方法获取锁
  3. 在要锁的代码后调用 unlock方法释放锁
  4. 如果有异常在异常后面的finally代码里面写unclock 可保证异常出现时正常释放锁

死锁

原理

l  同步锁里面又写了一个同步

l  程序中出现了无限等待

l  前提必须是多线程出现同步嵌套

l  线程进入同步获取锁 不出去同步不会释放锁

l  第一个人需要第二个人的锁 第二个人有需要第第一个人的锁

模拟实现

l  定义两个锁对象 A B

  1. 需要定义两个类
  2. 并且建立私有构造方法 是外类不能新建实例
  3. 然后提供一个静态final对象 让外类直接使用 但不可更改

 

l  循环用奇数偶数确定线程1 和线程2

 

 

 

l  然后一个测试类

  1. 创建两个线程来执行run方法
  2.  

 

l  程序运行结果 程序永远都不会停止运行

 

  1. 前几次都是抢占成功的
  2. 最后两次 第一次  执行偶数循环,获取了a锁,但是还没进入b 锁,就被奇数循环抢占了,获取了b锁
  3. 此时第一次需要b锁才能继续执行   第二次需要a锁才能继续执行
  4. 那么此时谁都拿不到所需的资源 所以就死锁了

线程等待和唤醒

概述

l  又叫线程通信

l  多个线程处理同一个资源

l  每个线程任务不一样

l  如果要合理的运用资源

l  就需要通过一种手段使各个线程能有效的利用资源

l  这种手段就叫做 等待唤醒机制

l  比如售票 之前只是减票 现在有的线程需要加票

示例

l  资源类

  1. 定义公共两个成员变量

 

l  两个线程类 输入 输出

  1. 输入

 

  1. 输出

 

l  测试类

 

 

因为有两个对象

l  解决

  1. 死锁 资源类中写私有对象 让外类通过调用新建实例
  2. 在输入类和输入类中 写一个可接受资源类对象的构造器
  3. 然后在main方法中 新建一个资源类对象 传入输出类和输入类的构造方法中
  4. 结果

 

  1. 出现了性别乱套

l  解决

  1. 问题出现原理

a)         输入类抢到了cpu 进行赋值  张三 男

b)         赋值 完 输出没有抢到cpu

c)         输入类仍然抢到了cpu  进行赋值 lisi

d)         刚赋值完lisi 还没赋值nv

e)         输出类抢到了cpu资源 就直接输出 了 lisi nv

f)          此时就出现了 性别乱套

 

  1. 解决

a)         只有一种方法加同步锁

b)         找共享数据

c)         在输入类中加锁

 

输出类加入锁

 

还是没解决

 

l  解决

  1. 原因

a)         两个线程是不是同一个锁

  1. 将对象锁this改为对象锁为 资源对象 r
  2. 结果 解决了问题

 

案例分析

l  最终目标 一个输入 一个输出 交替出现

l  线程只会执行run方法 不分赋值和取值

l  理想状态应该是 一次赋值一次打印

l  只有上一次赋值输出后 下一次赋值才能开始

l  反过来 输出一次后 必须等待下一次输入完毕后才能进行输出

l  实现步骤

  1. 输入:赋值后执行方法wait永远等待
  2. 输出 变量值打印输出后 notify输入唤醒 然后输出执行wait永远等待
  3. 输入:被唤醒后,重新对变量赋值 赋值后必须唤醒输出的线程botify 输入wait

实现

l  为了保证程序执行 输入首先拿到cpu执行权

l  在资源类中加一个变量boolean flag

l  flage为真 说明赋值完成

l  flage为假 说明获取值完成

l  输入 需要判断标记 flage是否为真

如果为真  则等待

如果为假 就进行赋值 并把标记改为false

l  输出也是如此

 

l  示例

  1. 加变量值

 

输入

 

输出

 

结果 抛出了异常

 

异常

 

就是说唤醒和等待方法 调用者错了

应该是锁对象 调用

修改

 

 

l  结果

 

java自学之路-day10

JAVA10Eclipse快捷键补充l 选中类CtrlT继承树l Ctrl或者f3查看源码多态会跳转到调用父类中l Java中lang包中的所有类不需要导包直接用 例如SystemStringl Ecplise中的JreSystemLibrary是默认的eclipse依赖jre的类库在该位置可以查... 查看详情

java自学之路-day19

Day19JDBC概述l Java数据库连接l 是一种执行SQL语句的javaAPIl 可以为多种数据库提供统一访问l 就是一组类和接口l 是java访问数据库的规范l 实现类由数据库厂商提供l JDBC需要连接驱动驱动是两个设备要进行... 查看详情

java自学之路-day06

JAVA06引用数据类型数组类接口也是一种引用类型用于定义属性和功能对现实中的事物的描述 例如学生类的定义 格式自定义数据类型publiccalss类名{属性和方法属性定义 修饰符数据类型变量名=值方法定义 修饰符返... 查看详情

java自学之路-day11

JAVA11正则表达式l 概念是一个字符串满足一定的规则qq号码检查[1-9][0-9][4,9]检查某些字符是否合规例如用户名是否合规一个[]代表一个或者多个字符为了解决String处理一些问题的太复杂l 匹配规则字符xa)    &nb... 查看详情

java自学之路-day14

JAVA14异常引入l Java代码在运行时期发生的问题就是异常l Java中把异常信息封装成了一个类l 当出现了问题时,就会创建异常类对象并抛出异常相关的信息l 如异常出现的位置原因等继承体系l java.lang类Throwable ... 查看详情

java自学之路-day16

JAVA16IO流转换流引入l 中文系统默认编码表GBKl FileWriter的构造方法假定默认编码GBKl 但是一些文本文件有可能是其他编码方式 l 所以引入转换流可以对编码表进行设定l 对之后开发互联网程序很重要 概述l... 查看详情

java自学之路-day15

JAVA15IOIO概述l i/o全称:input/outputl 之前的程序都是在内存中,一旦结束就没有了l 如果需要永久使用这些数据就需要持久化存储l 需要用到IO技术将数据放到持久化设备l Output写Input读 IO操作两种方方式File类... 查看详情

java自学之路-day02

JAVA02Variable变量l 数据类型四类八种byte8位1个字节short16位2个字节floatint32位4个字节longdouble64位8个字节字符布尔String是引用类型l 和基本类型使用方法一样变量定义使用注意事项l 不赋值不能使用不使用编译可以通过如... 查看详情

java自学之路-day20

JAVA20网络编程网络通信协议l 计算机网络中的各个电脑可以互传数据l 传输数据有一定的规则就是网络协议l 对数据的传输格式速率步骤都有规定l 必须遵循规则才能传输数据l 有很多种,最广泛的是TCP/IP和UDPl&nb... 查看详情

java自学之路-day21

JAVA21类加载器类的加载l 当程序要使用某个类时,如果还没被加载到内存中,系统会就会通过加载连接初始化三个步骤对这个类进行初始化l 加载类的加载器将class文件读入内存,放入方法区,并为之创建一个Class对象是编... 查看详情

java自学之路-day18

数据库数据库概念l 对于一串数据修改其中的一条数据l 如果用io流就需要全盘读写然后找到其中的一行进行修改l 或者使用数组进行修改l 这样太复杂效率慢所以需要引用数据库l 数据库本质是一个文件系统可... 查看详情

我的html自学之路--day1

1:HTML简介是一种超文本标记语言2:HTML标签是由尖括号包围的关键字,通常是成对出现,第一个表示开始标签,第二个表示结束标签。3:web浏览器:谷歌OpenGLfirfoxsafairIE4:HTML网页结构:<!DOCTYPEhtml><html><head><metacharset="u... 查看详情

java自学之路

JAVA自学之路一:学会选择为了就业,不少同学参加各种各样的培训。决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机、嵌入式、游戏、3G、测试等。那么究竟应该选择什么方向呢?我的意见是,不要太过相信各... 查看详情

java自学之路

Java自学之路前言从运行第一个程序开始算起,我接触编程也有三年的时间了。最初是从51单片机入门学习的C语言,班里面的大佬带着我一起做小项目,但是因为没人教,基本靠自学,学得慢,写的代码也烂,很没有章法。后来... 查看详情

如何自学java快速实现月薪过万?java自学之路

Java语言经历了20多年的发展,在C、C++语言占据大半江山的情况下横空出世,杀出了一条血路,面临PHP、Python、Ruby等动态语言也毫不显怯,至今仍是最受欢迎的编程语言,没有之一,可以说Java是面向对象语言的后起之秀和典范。... 查看详情

javaweb自学之路

一、Java学习路线 第一阶段:Java基础,包括java语法,面向对象特征,常见API,集合框架;(基础) 第二阶段:java界面编程,包括AWT,事件机制,SWING,(不常用)这个部分也可以跳过,用的时候再看都能来及; 第三阶... 查看详情

0基础java自学之路(2021年最新版)

...PS,支撑淘宝双11商品浏览需要哪些技术前言如果你想自学Java,认真看完本文,你以后的职场生涯至少少走1年弯路。本文会持续更新,建议收藏。初衷在CSDN上经常有同学私聊我询问“如何自学Java”、“想转行Java... 查看详情

0基础java自学之路(2021年最新版)

...PS,支撑淘宝双11商品浏览需要哪些技术前言如果你想自学Java,认真看完本文,你以后的职场生涯至少少走1年弯路。本文会持续更新,建议收藏。初衷在CSDN上经常有同学私聊我询问“如何自学Java”、“想转行Java... 查看详情