线程相关的概念

单线程情况: 同时只能执行一个任务,多个用户只能先后依次访问网站
多线程情况: 同时执行多个任务,多个用户同时访问网站
多线程的好处让程序可以”同时”做多件事情

并行

多个事件在同一时刻,同时执行。

并发

多个事件在同一时刻,交替执行。

进程概念

是一个正在运行的程序

进程的三个特性

1.独立性:进程与进程相互独立,各自占据内存空间。
2.动态性:程序是静止的,进程是动态的、进程会动态的占据内存空间、CPU、网络等资源
3.并发性:多个进程一起竞争CPU来运行自己。

线程概念

线程是进程的执行单元通俗的说: 线程就是来执行代码的
一个进程最少有一个线程
一个进程也可有多个线程, 称为多线程程序
一个进程最少有一个线程一个进程也可有多个线程, 称为多线程程序

说出多线程运行原理

CPU在多个线程间快速切换, 造成”同时”运行的假象。

多线程的实现方式

Java中实现多线程的方式有多种

1.继承Thread类的方式
2.实现Runnable接口的方式
3.实现Callable接口的方式

Thread类介绍

Thread类表示线程,通过Thread类启动多个线程。

Thread类启动线程步骤

定义类继承Thread类
重写run方法,编写新线程要执行的代码
创建子类对象
调用start()方法

注意

多线程程序随机并发执行

优缺点

优点:编码简单
缺点:线程类已经继承Thread,无法继承其他类,不利于扩展
第一种方式是继承哪个类,重写哪个方法,如何启动继承
Thread类、重写run方法,调用start()方法启动。
第一种方式的弊端是什么?
线程类已经继承Thread,无法继承其他类,不利于扩展。

为什么要重写run()

方法因为run()方法是用来封装被线程执行的代码

run()方法和start()方法的区别

run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。
start():启动新线程,新线程自动调用run()方法。

为什么要先启动子线程,再执行主线程任务

避免主线程任务提前执行完毕了。

多线程的实现方式

public Thread(Runnable target) //根据Runnable对象创建线程对象

实现Runnable接口启动线程步骤

1. 定义一个类MyRunnable实现Runnable接口
2.在MyRunnable类中重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数
5.调用start()方法启动线程
image.png
image.png

优缺点

优点:可以继续继承类和实现接口,扩展性强。
缺点:代码复杂一点,需要创建两个对象。

两种方式的对比

  1. 优点 缺点<br />继承Thread 编程比较简单,可以直接使用Thread类中的方法 可以扩展性较差,不能再继承其他的类<br />实现Runnable接口
  2. 扩展性强,实现该接口的同时还可以继承其他的类 编程相对复杂,不能直接使用Thread类中的方法

了解匿名内部类创建线程

方法参数是接口

传入接口的实现类对象
传入匿名内部类对象
public Thread(Runnable target) //根据Runnable对象创建线程对象
image.png

Thread常用API说明

Thread常用方法:获取线程名称getName()、设置名称setName()、获取当前线程对象currentThread()和sleep()等。 Thread类的其他方法如:yield、join、interrupt、不推荐的方法 stop 、守护线程、线程优先级等线程的控制方法,在开发中很少使用,这些方法会在就业加强以及后续需要用到的时候再为大家讲解。

线程类的常见方法

image.png

掌握获取和设置线程名称

image.png
image.png

掌握获得当前线程的对象(上面图片就是)

掌握线程休眠 public static void sleep(long time) //让线程休眠指定的时间,单位为毫秒
image.png

注意

此方法是Thread类的静态方法,可以直接使用Thread类调用。
这个方法是哪个线程执行的,哪个线程就会睡眠。

掌握电影院卖票案例

image.png
image.png
image.png

线程的安全问题

理解线程同步思想

image.png

线程同步的核心思想

加锁,把共享资源进行上锁,每次只能一个线程进入,操作完毕以后解锁,然后其他线程才能进来。

掌握同步代码块解决线程安全

image.png

掌握同步方法解决线程安全

image.png
image.png
image.png
image.png

掌握Lock锁解决线程安全

image.png
image.png
image.png

线程通信

void wait()//导致当前线程等待
void notify()//唤醒正在等待的单个线程
void notifyAll()//唤醒正在等待的所有线程

注意

上述方法必须使用锁对象在同步代码块中调用进行调用

sleep和wait的区别

sleep睡眠时不会释放锁
wait等待时会释放锁

案例

厨师(生产者)
如果桌子上没有包子就生产包子并且唤醒吃货。如果桌子上有包子就唤醒吃货并且自己等待。
吃货(消费者)
如果桌子上没有包子就唤醒厨师并且自己等待。如果桌子上有包子吃掉包子并且唤醒厨师。
image.png
什么是线程通信
多线程通过共享数据和线程相关API对线程执行过程一定的控制。

线程状态

生活中人的的状态

image.png

介绍Java线程的6种状态

Java线程的状态介绍

是线程从生到死的过程,以及中间经历的各种状态及状态转换。
理解线程的状态有利于提升并发编程的理解能力。

Java把线程的状态都放在了Thread类中的内部枚举State中。
总共定义了6种状态。
image.png
image.png

介绍线程状态的转换

线程生命周期

死锁

image.png
image.png

线程池

了解线程池的概念和好处

image.png

线程池介绍

image.png

说出线程池的概念

线程池是一个容器,可以保存一些长久存活的线程对象。

线程池的优势

1.提高响应速度,减少了创建新线程的时间。
2.降低资源消耗,重复利用线程池中线程,不需要每次都创建、销毁 。
3.便于线程管理,线程池可以集中管理并发线程的数量。

Executors工具类创建线程池

image.png
static ExecutorService newFixedThreadPool(int nThreads) //创建一个线程池,该线程池固定数量的线程

提交Runnable任务的使用步骤

1.创建线程池
2.
3.提交任务
线程池
image.png
创建Runnable任务
image.png

Callable接口介绍

public interface Callable { V call() throws Exception; }

Callable方式好处

1.有返回值
2.可以抛异常

线程池的使用步骤

1.创建线程池
2.创建Callable任务
3.提交任务
image.png
创建Callable任务
image.png

线程池的练习

image.png

image.png

了解ThreadPoolExecutor创建线程池(面试专用

image.png

新任务拒绝策略

ThreadPoolExecutor.AbortPolicy //丢弃任务并抛出RejectedExecutionException异常。是默认的策略
ThreadPoolExecutor.DiscardPolicy //丢弃任务,但是不抛出异常 这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy//抛弃队列中等待最久的任务 然后把当前任务加入队列中
ThreadPoolExecutor.CallerRunsPolicy//由主线程负责调用任务的run()方法从而绕过线程池直接执行
image.png