线程创建的三种方式

目录

1. Thread类

2. Runnable接口

3. Callable接口

4. 线程的生命周期

新建 

就绪

运行

阻塞

等待

结束


1. Thread类

继承Thread类的方式创建线程

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务
  2. 创建Thread类的子类,即创建了线程对象
  3. 调用线程对象的start()方法来创建并启动线程
  4. 线程创建的三种方式_第1张图片

2. Runnable接口

定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体就是线程的线程执行体

创建Runnable接口的实现类,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象

线程创建的三种方式_第2张图片

3. Callable接口

  1. 创建Callable接口的实现类,并实现call()方法。该call()方法将作为线程的执行体,旦该call()方法有返回值,再创建Callable实现类的实例。
  2. 使用Future Task类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
  3. 使用FutureTask对象作为Thread对象的target创建井启动新线程。
  4. 使用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

线程创建的三种方式_第3张图片

大部分人熟知的都是继承Thread类或实现Runnable接口,但上述两种方式来执行的线程其实都是没有返回值的,如果我们想要通过线程的执行获得一些有用的信息的话,那么通过继承Thread类或实现Runnable接口都是无法办到的。

比如说我们在实现一个商品的详情页的时候,可能需要获取商品的详细信息包括库存信息,商品详情,配送时效,商品评价等等一些信息的时候,如果我们在同一个线程中一次性查询这么多信息,那接口性能就可想而知了。 这个时候我们可能就会想到通过多线程的方式来并发的调用不同的接口,同时获取这些信息。这个时候,就该使用Callable接口来获取对应的返回值了。

当然,我们在真正的开发过程中一般也不会通过实现Callable接口的方式来实现功能,可能更多的是通过线程池来实现,关于线程池的东西我们在后面再来一起看看~~

4. 线程的生命周期

新建 

        new关键字创建线程对象时的状态

就绪

        通过线程对象的start()方法启动线程时对应的状态,此时线程并不一定马上能进入运行状态,线程的运行由操作系统的调度程序控制

运行

        线程获得cpu的执行权,线程正在执行需要执行的代码

阻塞

        BLOCKED称为阻塞状态,或者说线程己经被挂起,它“睡着”了,原因通常是它在等待一个“锁〞

        线程在等待一个“锁”,当尝试进入一个synchronized语句块/方法时,锁己经被其它线程占有,就会被阻塞,直到另一个线程走完临界区或者发生了相应锁对象的wait()操作后,它才有机会去争夺进入临界区的权利。

线程创建的三种方式_第4张图片 

 如上图可以看出,线程1在进入run方法时,由于线程0持有的锁还未释放,此时线程进入阻塞状态,等待线程0释放锁之后,才重新争夺运行权,从而再次进入运行态。

等待

        分为有限期等待(比如Thread.sleep() )和无限期等待( 比如:没有设置timeout参数的wait() )

结束

        线程结束

 

你可能感兴趣的:(JUC,java,开发语言)