线程与进程
多线程技术概述
进程
是指一个内存中运行的运行程序,每个进程都有一个独立的内存空间
线程
1 是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程至少有一个线程
2 线程实际上是在进程基础上的进一步划分,一个进程启动后,里面的若干执行路径又可以划分成若干个线程
线程调度
分时调度:
所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间
抢占式调度:
同步与异步
同步:排队执行,效率低,但是安全
异步:同时执行,效率高,但是数据不安全
并发与并行
并发:指两个或多个事件在同一个时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
实现多线程
继承Thread类
实现Thread类,并复写其run方法,通过start方法启动
每个线程都有自己的栈空间,共用一份堆内存
实现Runnable接口
1 创建一个任务对象
2 创建线程,并把创建的任务对象传过去
3 执行线程
优点:
1 通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行相同任务的情况
2 避免了单继承带来的局限性
3 任务与线程分离,提高了程序的健壮性
4 后续的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
Thread类
守护线程daemon 用户线程
设置和获取现成的名称
Thread.getName() 获取线程名称
Thread.setName() 设置线程名称
Thread.currentThread() 获取当前正在执行的线程
线程休眠sleep
Thread.sleep(Long millies) 线程休眠指定时间
线程阻塞
可以理解为比较耗时的操作
线程的中断
一个线程是一个独立的执行路径,他是否应该结束,应该由其自身决定
// 线程中断
Thread.initerrupt(); 为线程添加中断标记,线程会抛出中断异常,进入catch块,然后程序员自定义线程的处理方法,决定是否结束
线程,释放资源等,结束线程的最简单方法,就时直接return;
守护线程
线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何的存活的用户线程时,进程结束
守护线程:用于守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡
Thread.setDaemon(true) 设置线程为守护线程
线程安全问题
// 卖票问题
线程不安全解决方案
###线程安全1 - 同步代码块
关键字: synchronized
格式:
synchronized(锁对象) {
// 代码
}
多线程要使用“同一把锁”
线程安全2 - 同步方法
在方法声明上添加synchronized关键字
使用的锁是this对象,也就是创建的这个对象,执行这个方法的对象;
若是静态方法,则锁为this.class的class文件
当synchronized同步方法中使用同步代码块时,不同位置看的是同一把锁,其他线程不能执行
线程安全3 - 显式锁Lock
自己创建锁,自己进行加锁和释放
Lock lock = new ReentrantLock();
lock.lock(); // 加锁
lock.unlock() // 释放锁
公平锁和非公平锁
创建锁Lock时,传递参数:
true:公平锁,谁先访问的,谁就先执行
false/默认:线程抢夺锁,谁抢到,谁执行
线程死锁
在任何有可能产生锁的方法中,不要再调用另外一个能产生锁的方法
// 警察和罪犯
多线程通信
// 生产者和消费者
生产者和消费者
// 代码
线程的六种状态
NEW 线程新创建时
RUNNABLE 执行中
BLOCKED 阻塞状态
WAITING 无限等待
TIMED_WAITING 定时等待
TRMINATED 已退出的线程
带返回值的线程Callable
实现线程的:实现Callable接口;
FetureTask<T> task = new FutureTask<>(callable);
new Thread(task).start()
线程池概述
// 创建线程
// 创建任务
// 执行任务
// 关闭线程
定长线程池
定长线程池:长度是指定的数量
Executors.newFixedThreadPool(线程数量)
任务加入后的执行流程
1 判断线程池是否存在空闲线程
2 存在则使用
3 不存在的空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
4 不存在空闲线程,且线城市已满的情况下,则等待线程池存在空闲线程
单线程线程池
执行流程:
1 判断线程池的线程是否空闲
2 空闲则使用
3 不空闲,则等待,等待线程池中的单个线程空闲后在使用
周期定长线程池
Executors.newScheduledThreadPool(线程数量)
周期任务 定长线程池
执行流程:
1 判断线程池是否存在空闲线程
2 存在则使用
3 不存在空闲线程,且线程池未满的情况下,则放入线程池,然后使用
4 不存在空闲线程,且线程池已满,则等待线程池存在空闲线程
定时执行一次
参数1:定时执行的任务
参数2:时长数字
参数3:市场数字的时间单位,TimeUnit的常量指定
周期性执行任务:
参数1:任务
参数2:延迟时长数字(第一次执行是在什么时间以后)
参数3:周期时长数组(每隔多久执行一次)
参数4:时长数字的单位
Lambda表达式
函数式编程思想
面向对象:创建对象调用方法,解决问题