Java源码剖析34讲学习笔记~3

线程的状态有哪些? 它是如何工作的?

1. 线程状态

public enum State {
    
    
    /*
     * 新建状态
     * - 线程被创建出来, 但尚未启动时的线程状态
     */
    NEW,
    /*
     * 就绪状态
     * - 表示可以运行的线程状态, 它可能正在运行, 或者是在排队等待操作系统给它分配CPU资源
     */
    RUNNABLE,
    /*
     * 阻塞等待锁的线程状态
     * - 表示处于阻塞状态的线程正在等待监视器锁
     * - 比如等待执行synchronized代码块或者使用synchronized标记的方法
     */
    BLOCKED,
    /*
     * 等待状态
     * - 一个处于等待状态的线程正在等待另一个线程执行某个特定的动作
     * - 比如, 一个线程调用了Object.wait()方法
     * - 那它就在等待另一个线程调用Object.notify()或Object.notifyAll()方法
     */
    WAITING,
    /*
     * 计时等待状态
     * - 和等待状态(WAITING)类似, 它只是多了超时时间
     * - 比如调用了有超时时间设置的方法Object.wait(long timeout)
     *   和 Thread.join(long timeout)等这些方法时它才会进入此状态
     */
    TIMED_WAITING,
    /*
     * 终止状态
     * - 表示线程已经执行完成
     */
    TERMINATED
}

线程状态

2. 延伸面试题

线程一般会作为并发编程的起始问题, 用于引出更多的关于并发编程的面试问题

  • BLOCKED(阻塞等待) 和 WAITING(等待) 有什么区别?

    • BLOCKED 处于活跃状态, 等待其他线程使用完锁资源后继续运行

    • WAITING 处于休眠状态, 需被其他线程唤醒才能继续运行

  • start() 方法和 run() 方法有什么区别?

    • start()

      • 属于Thread自身, 并且使用了synchronized来保证线程安全
      • 可以开启多线程, 让线程从NEW状态转换成RUNNABLE状态
      • 只可调用一次, 否则会抛出 java.lang.IllegalStateException
    • run()

      • 属于Runnable的抽象方法, 必须由调用类重写此方法

      • 只是一个普通的方法

      • 可以多次调用

  • 线程的优先级有什么用? 该如何设置?

    // 线程可以拥有的最小优先级
    public final static int MIN_PRIORITY = 1;
    
    // 线程默认优先级
    public final static int NORM_PRIORITY = 5;
    
    // 线程可以拥有的最大优先级
    public final static int MAX_PRIORITY = 10;
    
    
    // 通过Thread.setPriority()来设置优先级
    public final void setPriority(int newPriority) {
          
          
        ThreadGroup g;
        checkAccess();
        // 先验证优先级的合理性
        if(newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
          
          
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
          
          
            // 优先级如果超过线程组的最高优先级, 则把优先级设置为线程组的最高优先级
            if(newPriority > g.getMaxPriority()) {
          
          
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }
    
  • 线程的常用方法有哪些?

    • join()

      public final synchronized void join(long millis) throws InterruptedException {
              
              
          long base = System.currentTimeMillis();
          long now = 0;
      	// 超时时间不能小于0
          if (millis < 0) {
              
              
              throw new IllegalArgumentException("timeout value is negative");
          }
      	// 等于0表示无限等待, 直到线程执行完为止
          if (millis == 0) {
              
              
              // 判断子线程(其他线程)为活跃线程, 则一直等待
              while (isAlive()) {
              
              
                  wait(0);
              }
          } else {
              
              
              // 循环判断
              while (isAlive()) {
              
              
                  long delay = millis - now;
                  if (delay <= 0) {
              
              
                      break;
                  }
                  wait(delay);
                  now = System.currentTimeMillis() - base;
              }
          }
      }
      
    • yield()

      // 由 C 或者 C++ 实现的
      /*
       * 给调度程序的提示是当前线程愿意放弃对处理器的当前使用。
       * 调度程序可以随意忽略此提示。
       * Yield是一种启发式尝试,旨在提高线程之间的相对进程,否则将过度利用CPU。
       * 应将其使用与详细的性能分析和基准测试结合起来,以确保它实际上具有所需的效果。
       * 很少适合使用此方法。
       * 它可能对调试或测试有用,因为它可能有助于重现由于竞争条件而产生的错误。
       * 当设计诸如{@link java.util.concurrent.locks}包中的并发控制结构时,它也可能很有用。
       */
      public static native void yield();
      

猜你喜欢

转载自blog.csdn.net/CJG753951/article/details/107192888