线程
概念
多线程
多任务执行,多路径执行
优点
提高性能
提高效率
进程与线程之间的区别
进程
系统中的程序,一个进程之间可以包含1~n个线程,系统中资源分配的最小单位,每个进程都有自己的代码与数据空间,进程之间的切换开销较大
线程
程序中的顺序流,线程是cpu调度与执行的最小单位,多个线程之间共享进程的代码和数据空间,每一个线程都有自己的程序计数器运行栈,线程之间切换开销较小
一个cpu同一时刻只能调度一个线程
创建线程
继承Thread,重写run方法
继承Thread,重写run方法 + start开启线程
实现Runnable接口,重写run方法(推荐)
实现Runnable接口,重写run方法+start开启
优点
接口多实现,类的单继承
实现资源共享
重写方法对异常抛出的要求
重写方法上抛出的异常类型<=被重写方法上异常的抛出类型
可用匿名内部类lambda表达式简写
实现Callable接口,重写call方法
实现juc包下的Callable接口,重写call方法 + 线程池
优点
call方法可以抛出异常,可以定义返回值,run方法不可以
线程的状态
5种状态
新生状态
new
就绪状态
线程进入到就绪状态
1.start()
2.阻塞解除
3.cpu的调度切换
4.yield 礼让线程
当线程执行到yield方法,会让出cpu的资源,同时线程会恢复就绪状态
运行状态
阻塞状态
一个线程如果进入到阻塞状态,阻塞解除之后,不能直接恢复到运行,会直接恢复高就绪状态,等待cpu的调度
线程进入阻塞状态
1.sleep()
线程休眠
static void sleep(long millis)
导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。
static void sleep(long millis, int nanos) 执行ms+ns
当一个线程调度sleep进入睡眠状态,让出cpu的资源
抱着资源睡觉: 这个资源不是cpu的资源, 值的是对象的锁资源
作用
放大问题出现的可能性
模拟网络延迟
2.join() 插队线程
插队线程
A线程执行过程中,如果B线程插队了,A线程就会进入到阻塞状态,等待插队线程执行完毕|等待执行的时间,A线程会恢复到就绪状态
void join() 等待这个线程死亡。
void join(long millis) 此线程最多等待 millis毫秒。
void join(long millis, int nanos) 此线程最多等待 millis毫秒加上 nanos纳秒。
3.wait() 等待
4.IO
终止状态
一个线程如果一旦进入终止状态,不可恢复
线程进入终止状态
1.正常执行完毕
2.stop() 过时--> 不推荐使用
3.通过标识判断
Thread.State getState() 获取线程状态
线程可以处于以下状态之一
NEW : new Thread()
尚未启动的线程处于此状态。
RUNNABLE : 就绪|运行
在Java虚拟机中执行的线程处于此状态。
BLOCKED : 等待对象锁的阻塞状态
被阻塞等待监视器锁定的线程处于此状态。
WAITING : wait(),join()等
无限期等待另一个线程执行特定操作的线程处于此状态。
TIMED_WAITING : 与时间相关的等待,sleep(ms),join(ms),wait(ms)...
正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。
TERMINATED : 终止
已退出的线程处于此状态。
线程通信
生产者消费者模式
生产者用来生产商品,消费者就是消费产品
Object类中wait()等待,notify()唤醒,notifyAll()唤醒全部
wait() 等待
等待,通过对象调用wait()方法让当前进入等待阻塞状态,会进入到调用wait方法对象的等待池中进行等待,等待被唤醒
让出cpu的资源,同时释放对象的锁
notify() 唤醒
唤醒对象等待池中正在等待的线程,被唤醒的线程进入到就绪队列,需要被cpu调度同时获取对象锁才能执行
wait()与notify()必须使用在同步环境下,用来协调多线程对共享数据存储的问题,否则会抛出异常 IllegalMonitorStateException如果当前线程不是此对象监视器的所有者
线程安全问题
原因
当多个线程同时操作同一份资源,才有可能出现线程不安全问题
同步锁synchronized
有可能出现数据不安全的代码段,让多个线程排队执行
同步的使用
同步条件
协调多个线程排队执行的条件
对象的锁
同步的代码
需要多个线程排队执行的代码
synchronized用法
修饰方法 : 同步方法
同步实例方法
条件
调用成员方法的对象
代码范围
整个方法体
优缺点
优点
简单,直接同步整个方法体
缺点
代码范围太大,效率较低
同步静态方法
条件
锁类->锁的类的Class对象->一个类只有一个,加载到内存中究存在Class对象,不变,唯一
代码范围
整个方法体
修饰块 : 同步块
synchronized(条件){排队执行的代码;}
条件
类名.class
锁类
锁类相当于锁住了这个类的所有对象,如果只想要锁当前类的某一个对象,建议锁那一个具体的对象this
this
成员方法中this默认指代当前调用成员方法的对象
如果锁this,就是锁一个对象,相当于锁住了这个对象的所有资源(成员),如果指向锁一个对象的某一个资源,建议可以直接锁资源
资源
锁对象,锁不变的内容
自定义引用数据类型的对象地址永远不变
注意
同步的代码范围太大,效率太低
同步的代码范围太小,锁不住,不安全
线程中断
void interrupt()
为线程添加一个中断标识
boolean isInterrupted()
测试此线程是否已被中断,是否曾经调用过interrupt方法添加了中断标识
static boolean interrupted()
测试当前线程是否已被中断,是否曾经调用过interrupt方法添加了中断标识,同时复位标识
注意
当调用sleep方法线程睡眠时
InterruptedException
如果有任何线程中断了当前线程。 抛出此异常时,将清除当前线程的中断状态 。