深入浅出吃透多线程、线程池核心原理及代码详解

本文深入探讨了多线程的核心概念,包括线程生命周期、状态描述、线程优先级以及线程的实现方式。接着,详细解释了线程池的工作原理,分析了线程池的初始化、执行流程、核心线程与非核心线程的协作,并介绍了Java中常见的线程池类型。此外,还讨论了线程池的拒绝策略,以及如何选择合适的线程池类型。
摘要由CSDN通过智能技术生成

一、多线程详解

  1、什么是线程

  线程是一个操作系统概念。操作系统负责这个线程的创建、挂起、运行、阻塞和终结操作。而操作系统创建线程、切换线程状态、终结线程都要进行CPU调度——这是一个耗费时间和系统资源的事情。

腾讯认证T9后端开发岗位,linux服务器开发高级架构师系统学习视频点击:C/C++Linux服务器开发高级架构师/Linux后台架构师

B站7000+播放的线程池视频讲解:150行代码,手写线程池(完整版)

  2、线程生命周期

 线程通常都有五种状态,创建、就绪、运行、阻塞和死亡:

  • 创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
  • 就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
  • 运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
  • 阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
  • 死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。   

  可以用过jstack 或者idea debug快照显示状态,常见名词大致意思为:

  • "Low Memory Detector":负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间。
  • "CompilerThread0":用来调用JITing,实时编译装卸class。
  • "Signal Dispatcher":负责分发内部事件。
  • "Finalizer":负责调用Finalizer方法。
  • "Reference Handler":负责处理引用。
  • "main":是主线程。
  • "VM Thread", "VM Periodic Task Thread":从名字上看是虚机内部线程。

  3、线程状态描述

  • NEW:状态是指线程刚创建, 尚未启动。
  • RUNNABLE:状态是线程正在正常运行中, 当然可能会有某种耗时计算/IO等待的操作/CPU时间片切换等, 这个状态下发生的等待一般是其他系统资源, 而不是锁, Sleep等
  • BLOCKED:这个状态下, 是在多个线程有同步操作的场景, 比如正在等待另一个线程的synchronized 块的执行释放, 或者可重入的 synchronized块里别人调用wait() 方法, 也就是这里是线程在等待进入临界区
  • WAITING:这个状态下是指线程拥有了某个锁之后, 调用了他的wait方法, 等待其他线程/锁拥有者调用 notify / notifyAll 一般该线程可以继续下一步操作
  • TIMED_WAITING: 这个状态就是有限的(时间限制)的WAITING, 一般出现在调用wait(long), join(long)等情况下, 另外一个线程sleep后, 也会进入TIMED_WAITING状态
  • TERMINATED:这个状态下表示 该线程的run方法已经执行完毕了, 基本上就等于死亡了(当时如果线程被持久持有, 可能不会被回收)

  要区分 BLOCKED 和 WATING 的区别, 一个是在临界点外面等待进入, 一个是在理解点里面wait等待别人notify, 线程调用了join方法 join了另外的线程的时候, 也会进入WAITING状态, 等待被他join的线程执行结束。核心区别就是BLOCKED没拿到锁,WAITING拿到了锁。

  4、线程优先级Priority

  线程的优先级是将该线程的重要性传给了调度器、cpu处理线程顺序有一定的不确定,但是调度器会倾向于优先权高的先执行。

  5、线程实现方式

  线程有三种实现方式:Thread、Runnable、Callable。

  Thread实现方式代码如下:

public class Thread01 extends Thread {

   @Override
   public void run() {
      System.out.println("Thread 方式创建线程");
   }

   public static void main(String[] args) throws InterruptedException {
      new Thread01().start();//多线程
   }
}

  Runnable实现方式:

public class Runnable01 implements  Runnable {
   @Override
   public void run() {
      System.out.println("Runnable方式创建线程");
   }

   public static void main(String[] args) {
      new Thread(new Runnable01()).start();
   }
}

  Callable实现方式:

public class Callable01 implements Callable<String> {
   @Override
   public String call() throws Exception {
      System.out.println("Callable方式创建线程");
      return "Callable";
   }

   public static void main(String[] args) throws ExecutionException, InterruptedException {
      FutureTask task=new FutureTask(new Callable01());//有参 赋值 成员属性
      new Thread(task).start();
      System.out.println( task.get());;
   }
}

  6、Thread和Runnable的联系与区别

  • Runnable的实现方式是实现其接口即可。
  • Thread的实现方式是继承其类。
  • Runnable接口支持多继承,但基本上用不到。
  • Thread实现了Runnable接口并进行了扩展,而Thread和Runnable的实质是实现的关系,不是同类东西,所以Runnable或Thread本身没有可比性。public class Thread implements Runnable { // 省略 @Override public void run() { if (target != null) { target.run(); } } // 省略 }

  综上所述:Thread和Runnable的实质是继承关系,没有可比性。无论使用Runnable还是Thread,都会new Thread,然后执行run方法。用法上,如果有复杂的线程操作需求,那就选择继承Thread,如果只是简单的执行一个任务,那就实现runnable。

  7、Callable原理是什么

  Callable 1.5引入,具有返回值,并且支持泛型:

public interface Callable<V> {
    V call()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值