多线程
目录:
1.创建线程
2.守护线程
3.线程的生命周期
4.线程安全
5.线程可见性
6.线程的争抢
7.线程安全的实现方法
下面是我总结的多线程的思维导图
1.创建线程
(1)继承Thread类,重写run方法
(2)实现Runnable接口
Runnable是函数接口,如果想要让线程启动,必须调用Thread类中的start方法。
问题:实现了Runnable接口找不到Thread类中的start方法,怎么办?
答:构建一个Thread(代码如下)
使用箭头函数(lambda表达式)
简写:(代码如下图)
抛出线程终止异常
(3)实现Callable接口
借助FutureTask工具类。FutureTask是泛型类。
先把Callable转成FutureTask,再转成Runnable,最后转成Thread。
注:用lambda表达式的前提必须得是函数式接口
2.守护线程
创建守护线程(代码如下)
任何线程继承创建它的线程守护进程状态时,由于主线程是用户线程,因此在主方法内启动的任何线程默认都是守护线程。
3.线程的生命周期
NEW:这个状态主要是线程未被start()调用执行
RUNNABLE:线程正在JVM中被执行,等待来自操作系统的调度
BLOCKED:(锁)阻塞。因为某些原因不能立即执行,需要挂起等待
WAITING:无限期等待。Object类,如果没有唤醒,则一直等待。
TIMED_WAITING:有限期等待,线程等待一个指定的时间
TERMINATED:终止线程的状态,线程已经执行完毕
流程图如下:
等待和阻塞两个概念有点像。阻塞是因为外部原因,需要等待;而等待一般是主动调用方法,发起主动地等待。
等待分为两种等待,有限期等待和无限期等待。等待还可以传入参数确定等待时间。
sleep方法(代码如下)
join方法:本意是阻塞主线程
4.线程安全
(1)指令重排
(2)线程的可见性
(3)线程的争抢
5.线程的可见性
解决现成的可见性——用volatile关键字,加在访问权限符后。
volatile能够强制改变变量的读写直接在内存中操作。
6.线程的争抢
解决线程争抢的问题最好的办法就是【加锁】(synchronized)
synchronized同步锁,线程同步
当一个方法加上了synchronized修饰,这个方法就叫做同步方法。
7.线程安全的实现方法
(1)使用synchronized关键字
(2)使用volatile关键字
(3)使用ThreadLocal对各个线程进行隔离