Java 多线程基础

P1 多线程概述

学习路线:

  • 线程简介
  • 线程实现(重点)
  • 线程状态
  • 线程同步(重点)
  • 线程通信问题
  • 高级主题

线程、进程、多线程

核心概念:

  • 多任务:看起来多任务,其实同一时间,其实依旧只在做一件事
  • 多线程:多个方法同时执行;

  • 进程:一个程序开启一个进程,一个进程包含多个线程;
  • main() 称为主线程,为系统的入口,用于执行整个程序;
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

Process(进程)与Thread(线程):

  • 程序:是一个静态概念,包含指令和数据的有序集合。
  • 进程:程序执行的一次过程,是一个动态概念。进程是系统资源分配的单位。
  • 线程:字啊一个进程中,通常包含若干线程,一个进程至少有一个线程。线程是CPU调度和执行的单位。

注意:很多多线程是模拟出来的,真正的多线程是指多个CPU即多核。如果是模拟出来的多线程,在一个CPU的情况下,在同一个时间点上,CPU只能执行一个代码,因为切换的很快,才有同时执行的错觉。

P3 线程创建

Thread、Ruunnable、Callable:

  • 继承 Thread 类,重点
  • 实现 Runnable 接口,重点
  • 实现 Callable 接口,了解

P3 Thread

  • 自定义线程类,继承Thread类;
  • 重写 run() 方法,编写线程执行体;
  • 创建线程对象,调用该对象的start()方法启动线程;注意,不是调用 run() 方法!

注意点:

  • start() 方法启动多线程,线程不一定立即执行,CPU 安排调度;

P4 Runnable

  • 自定义线程实现类 P,实现 Runnable 接口;
  • 实现 run() 方法,编写线程执行体;
  • 创建线程实现类的对象 p;
  • 对象 p 传入 Thread类的构造器中,创建线程对象 r,调用对象 r 的 start() 方法启动线程;new Thread(p).start();

小结:

  • 推荐使用 Runnable 对象,因为 Java 单继承的局限性!

P6 初始并发问题

  • Thread.currentThread().getName() 获取当前线程的名字;
  • Thread.sleep(2000) 延时 2 秒;

多个线程操作同一个资源的情况下,数据紊乱(多人买到了同一个票)

P7 龟兔赛跑

Race race = new Race();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();

P8 Callable

  • 实现 Callable 接口,需要返回值类型;
  • 重写 call 方法,需要抛出异常;
  • 用接口实现类创建目标对象 t1
  • 创建执行服务 ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交执行:Future<Boolean> result1 = ser.submit(t1);
  • 获取结果:boolean r1 = result.get()
  • 关闭服务:ser.shutdownNow();

P9 静态代理

婚庆公司作为代理的例子。

总结:

  • 定义一个接口,里面定义了真实对象应该具有的方法名;
  • 真实对象的类去实现接口类;
  • 代理类也需要去实现接口类:
    • 定义一个接受真实对象的构造器
    • 重写接口方法,方法内做一些before/after 操作的同时,调用一些传入的真实对象的同名方法;

通俗来讲:代理去执行一个动作,看着像是代理做的,其实,他帮你做了一些事情的同时,还是真实的你去执行了某些方法!因为是真实的对象传进代理作为构造器的入参了!

为何在这里要介绍静态代理?因为线程接口底层应用的和它相似!

new Thread(()->System.out.println("test")).start();
new WeddingCompanny(new You()).marry();

P10 Lambda 表达式

  • 其实质属于函数式编程的概念,理解 Functional Interface(函数式接口)是学习 Java8 lambda 表达式的关键所在;
  • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口!
  • 对于函数式接口,我们可以通过lambda表达式来创建该接口的对象!

为什么要使用 lambda 表达式?

  • 避免匿名内部类定义过多;
  • 使代码更简洁;
  • 去掉没有意义的代码,只留下核心的逻辑;

总结:

  • lambda 表达式去掉方法体的花括号的前提是,只有一行代码,否则不能简化掉花括号;
  • 前提是接口是函数式接口! IPerson 是一个函数式接口,其中仅有一个方法;
  • 多个参数也可以去掉参数类型;IPerson p = (name,age)->System.out.println("name: "+name+" age: ":+age);——可以看到, -> 后面就是接口中定义的方法的重写!

P11 线程停止

线程有 5 大状态,待补充截图

  • 新生状态 new
  • 就绪状态 start
  • 阻塞状态
  • 运行状态
  • dead状态

线程方法:

  • setPriority()
  • sleep()
  • join()
  • yield()
  • interrupt() 不建议使用
  • isAlive()
posted @ 2020-03-10 09:18  Michael翔  阅读(173)  评论(0编辑  收藏  举报