多线程

目录:

  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对各个线程进行隔离