java自学之路-day17

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有多核心 那么同一时刻就能执行多个线程

迅雷下载

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. 父类中有一个构造方法可以改名称

Sleep方法

l  线程停止特定时间

l  抛异常

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

Runnable接口

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

l  实现接口Runnable

l  实现方法run

示例

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

原理

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

好处

匿名内部类实现线程程序

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

解决

  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

模拟实现

l  定义两个锁对象 A B

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

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

l  然后一个测试类

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

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  结果

时间: 2024-10-08 00:17:07

java自学之路-day17的相关文章

【转】JAVA自学之路

JAVA自学之路 一: 学会选择 为了就业,不少同学参加各种各样的培训. 决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机.嵌入式.游戏.3G.测试等. 那么究竟应该选择什么方向呢? 我的意见是,不要太过相信各种培训机构或是抢手文章的说法(包括我),当你要走向社会的时候,就不要再把自己当成学生,不要把自己的将来交给别人,学会运用自己的眼睛去观察,去了解这个世界吧. 每个培训机构都会宣传自己的好处,并不能说明大的趋势. 一些新闻文章很有可能是枪手写的,不必太过相信.国外背景的

[转载] JAVA自学之路

原文链接http://blog.csdn.net/mengxin846/article/details/2219844 虽然文章有点旧但还是有些启发的,譬如要事第一,好读书不求甚解. JAVA自学之路 一:学会选择 为了就业,不少同学参加各种各样的培训. 决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机.嵌入式.游戏.3G.测试等. 那么究竟应该选择什么方向呢? 我的意见是,不要太过相信各种培训机构或是抢手文章的说法(包括我),当你要走向社会的时候,就不要再把自己当 成学生

马士兵:JAVA自学之路

JAVA自学之路 一:学会选择 为了就业,不少同学参加各种各样的培训.决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机.嵌入式.游戏.3G.测试等. 那么究竟应该选择什么方向呢?我的意见是,不要太过相信各种培训机构或是抢手文章的说法(包括我),当你要走向社会的时候,就不要再把自己当成学生,不要把自己的将来交给别人,学会运用自己的眼睛去观察,去了解这个世界吧. 每个培训机构都会宣传自己的好处,并不能说明大的趋势.一些新闻文章很有可能是枪手写的,不必太过相信.国外背景的教师和课

Java 自学之路

Java 自学之路 前言 从运行第一个程序开始算起,我接触编程也有三年的时间了.最初是从51单片机入门学习的C语言,班里面的大佬带着我一起做小项目,但是因为没人教,基本靠自学,学得慢,写的代码也烂,很没有章法.后来大三下半学期开始准备考研(从电子跨考计算机),从零开始学习数据结构,这才算是真正地入了编程的门.至于考研,后来就放弃了(别问我为什么放弃,当时脑子抽了),去了一家小公司实习.这家公司主要做机器视觉的项目,当时去面试的时候觉得挺高大上,技术 leader 也挺和蔼,感觉是很务实的一个团队

Java自学之路---DotCom

引言 我从接触编程以来,一直是一个C/C++程序猿,因为我喜欢编程时,那种接地气的感觉,认为只有自己管理内存的使用,心理才踏实.但随着工作中不断增加的见闻,不断的从博客和源码中获得新的见解,我发现这个时代已经发生了变化,我们有强劲的硬件资源.我们有久经考验的框架和源码,我们最宝贵的是花在编码上的时间.所以我决定带着之前C/C++的经验,来认识JAVA是门怎样的语言,以及它的编程理念可以给我带来怎样的好处. 如何学习 和我学习其他语言一样,我主要还是依靠书本,电子书或者是纸质书,这样学习起来才是最

java自学之路-day16

JAVA16 IO流 转换流 引入 l  中文系统默认编码表GBK l  FileWriter的构造方法假定默认编码GBK l  但是一些文本文件有可能是其他编码方式 l  所以引入转换流 可以对编码表进行设定 l  对之后开发互联网程序很重要 概述 l  字符流的一种 l  字符与字节的桥梁 l  继承Writer类 OutputStreamWriter l  Java.io. OutputStreamWriter l  继承Writer类 l  字符输出流 向文本文件写入数据 l  字符流转

java自学之路-day18

数据库 数据库 概念 l  对于一串数据修改其中的一条数据 l  如果用io流就需要全盘读写 然后找到其中的一行 进行修改 l  或者使用数组进行修改 l  这样太复杂 效率慢 所以需要引用数据库 l  数据库本质是一个文件系统 可以看做是一个具有很好的处理数据能力的容器 和集合 数组 都一样 l  里面有严格的数据存储格式 l  数据库管理系统是用一个软件管理数据库 l  常见的数据库管理系统 MYSQL  开源免费 瑞典的公司开发 sun公司收购  Oracle收购了sun MYSQL6.x

java自学之路-day10

JAVA10 Eclipse快捷键补充 l  选中类Ctrl T 继承树 l  Ctrl 或者f3 查看源码 多态会跳转到调用父类中 l  Java中lang包中的所有类 不需要导包 直接用  例如 System String l  Ecplise 中的Jre System Library是默认的eclipse依赖jre的类库 在该位置可以查找到平常使用的String 类 Random类 Math类 l  Jdk 包括 jre和开发工具,jre包括jvm 和运行时所需要的核心类库 l  运行 h

java自学之路-day14

JAVA14 异常 引入 l  Java代码在运行时期发生的问题就是异常 l  Java中把异常信息封装成了一个类 l  当出现了问题时,就会创建异常类对象并抛出异常相关的信息 l  如异常出现的位置 原因等 继承体系 l  java.lang 类 Throwable   可以被扔出去的类 l  java中所有的错误和异常 l  直接已知子类: Error, Exception 异常和错误的区别 l  数组访问越界是异常 Exception RuntimeException 编译,运行期间出现的