创建线程方式

  1. 继承Thread类,重写run方法,调用start( )
  2. 实现Runnable接口,实现run方法,创建Thread并调用start( )
  3. 实现Callable接口,实现call方法,作为FutureTask<>构造参数创建FutureTask对象,创建Thread实例并调用start
  4. 创建Callable 或 Runnable任务,提交到线程池

Thread

Thread实现了Runnable接口,并且实现了接口的run方法。

Runnable

接口,只有一个run( )函数,函数没有返回值

Runnable对象可以传入到Thread类的构造方法中,通过Thread来运行Runnable任务,而Callable接口则不能直接传入到Thread中来运行,Callable接口通常结合线程池来使用。

Callable

接口,有call()函数,call( )函数有返回值

Future

Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

FutureTask

FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了**Futrue**这两个接口。

FutureTas实现了run 方法,调用了构造函数传入的Callable实现类的call方法,并且用result的变量接收方法的返回值,最后调用set方法将返回结果设置到类的属性。可以实现获取返回值以及判断线程是否运行完成、取消的能力。

Thread类

https://tva1.sinaimg.cn/large/007S8ZIlly1ghv30r2u2vj30w30lfjti.jpg

start( ) 和 run( )

start

启动一个新线程,处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行相应线程的run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止。start()不能被重复调用。用start方法来启动线程,真正实现了多线程运行。

run

run()不需要用户来调用的。当通过start()方法启动一个线程之后,一旦线程获得了CPU执行时间,便进入run()方法体去执行具体的任务。如果直接调用run方法,并不会启动新线程。程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行。

sleep( )

在指定的毫秒数内让当前正在执行的线程睡眠,并交出 CPU 让其去执行其他的任务。当线程睡眠时间满后,不一定会立即得到执行。调用sleep方法相当于让线程进入阻塞状态不会释放锁

yield( )

让当前线程交出CPU资源,让CPU去执行其他的线程。但是不能控制具体的交出CPU的时间。只能让 拥有相同优先级的线程 有获取 CPU 执行时间的机会。调用yield()方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新得到 CPU 的执行。不释放锁

join( )

如果调用的是无参join方法,则等待thread执行完毕;如果调用的是指定了时间参数的join方法,则等待一定的时间。

通过wait()方法 (Object 方法) 实现。当 参数millis == 0 时,会进入 while(isAlive()) 循环,并且只要子线程是活的,宿主线程就不停的等待。wait(0) 的作用是让当前线程(宿主线程)等待,所以,虽然是子线程对象(锁)调用wait()方法,但是阻塞的是宿主线程。释放锁(wait方法)。

interrupt( )

单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,也就是说,它可以用来中断一个正处于阻塞状态的线程。直接调用interrupt() 方法不能中断正在运行中的线程配合 isInterrupted()/interrupted() 能够中断正在运行的线程,因为调用interrupt()方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()/interrupted()判断中断标志是否被置位来中断线程的执行