JDK源码(20)-Thread

简介: JDK源码(20)-Thread

 一、概述

此线程指的是执行程序中的线程。 Java虚拟机允许应用程序同时执行多个执行线程。

每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护线程。

当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为main的方法)。 Java虚拟机将继续执行线程,直到发生以下任一情况:

    • 已经调用了Runtime类的exit方法,并且安全管理器已经允许进行退出操作。
    • 所有不是守护进程线程的线程都已经死亡,无论是从调用返回到run方法还是抛出超出run方法的run

    创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:

    class PrimeThread extends Thread {
             long minPrime;
             PrimeThread(long minPrime) {
                 this.minPrime = minPrime;
             }
             public void run() {
                 // compute primes larger than minPrime
                  . . .
             }
         }

    image.gif

    然后,以下代码将创建一个线程并启动它运行:

    PrimeThread p = new PrimeThread(143);
         p.start();

    image.gif

    另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:

    class PrimeRun implements Runnable {
             long minPrime;
             PrimeRun(long minPrime) {
                 this.minPrime = minPrime;
             }
             public void run() {
                 // compute primes larger than minPrime
                  . . .
             }
         }

    image.gif

    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143);
         new Thread(p).start();

    image.gif

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException

    二、属性、内部类和接口

    静态枚举类:线程状态

    public enum State {
            NEW,
            RUNNABLE,
            BLOCKED,
            WAITING,
            TIMED_WAITING,
            TERMINATED;
        }

    image.gif

    Thread.UncaughtExceptionHandler:当Thread由于未捕获的异常而突然终止时,处理程序的接口被调用。

    @FunctionalInterface
        public interface UncaughtExceptionHandler {
            /**
             * Method invoked when the given thread terminates due to the
             * given uncaught exception.
             * <p>Any exception thrown by this method will be ignored by the
             * Java Virtual Machine.
             * @param t the thread
             * @param e the exception
             */
            void uncaughtException(Thread t, Throwable e);
        }

    image.gif

    线程的最大、最小、默认优先级。默认为5。

    /**
         * The minimum priority that a thread can have.
         */
        public final static int MIN_PRIORITY = 1;
       /**
         * The default priority that is assigned to a thread.
         */
        public final static int NORM_PRIORITY = 5;
        /**
         * The maximum priority that a thread can have.
         */
        public final static int MAX_PRIORITY = 10;

    image.gif

    三、常用方法

    修饰符和返回值 方法名称及描述
    static int activeCount()

    返回当前线程的thread group及其子组中活动线程数的估计。

    void checkAccess()

    确定当前正在运行的线程是否有权限修改此线程。

    protected Object clone()

    将CloneNotSupportedException作为线程抛出无法有意义地克隆。

    static Thread currentThread()

    返回对当前正在执行的线程对象的引用。

    static void dumpStack()

    将当前线程的堆栈跟踪打印到标准错误流。

    static int enumerate(Thread[] tarray)

    将当前线程的线程组及其子组中的每个活动线程复制到指定的数组中。

    static Map<Thread,StackTraceElement[]> getAllStackTraces()

    返回所有活动线程的堆栈跟踪图。

    ClassLoader getContextClassLoader()

    返回此Thread的上下文ClassLoader。

    static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()

    返回当线程由于未捕获异常突然终止而调用的默认处理程序。

    long getId()

    返回此线程的标识符。

    String getName()

    返回此线程的名称。

    int getPriority()

    返回此线程的优先级。

    StackTraceElement[] getStackTrace()

    返回表示此线程的堆栈转储的堆栈跟踪元素数组。

    Thread.State getState()

    返回此线程的状态。

    ThreadGroup getThreadGroup()

    返回此线程所属的线程组。

    Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()

    返回由于未捕获的异常,此线程突然终止时调用的处理程序。

    static boolean holdsLock(Object obj)

    返回 true当且仅当当前线程在指定的对象上保持监视器锁。

    void interrupt()

    中断这个线程。

    static boolean interrupted()

    测试当前线程是否中断。

    boolean isAlive()

    测试这个线程是否活着。

    boolean isDaemon()

    测试这个线程是否是守护线程。

    boolean isInterrupted()

    测试这个线程是否被中断。

    void join()

    等待这个线程死亡。

    void join(long millis)

    等待这个线程死亡最多 millis毫秒。

    void join(long millis, int nanos)

    等待最多 millis毫秒加上 nanos纳秒这个线程死亡。

    void run()

    如果这个线程使用单独的Runnable运行对象构造,则调用该Runnable对象的run方法; 否则,此方法不执行任何操作并返回。

    void setContextClassLoader(ClassLoader cl)

    设置此线程的上下文ClassLoader。

    void setDaemon(boolean on)

    将此线程标记为 daemon线程或用户线程。

    static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

    设置当线程由于未捕获的异常突然终止而调用的默认处理程序,并且没有为该线程定义其他处理程序。

    void setName(String name)

    将此线程的名称更改为等于参数 name

    void setPriority(int newPriority)

    更改此线程的优先级。

    void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

    设置当该线程由于未捕获的异常而突然终止时调用的处理程序。

    static void sleep(long millis)

    使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。

    static void sleep(long millis, int nanos)

    导致正在执行的线程以指定的毫秒数加上指定的纳秒数来暂停(临时停止执行),这取决于系统定时器和调度器的精度和准确性。

    void start()

    导致此线程开始执行; Java虚拟机调用此线程的run方法。

    String toString()

    返回此线程的字符串表示,包括线程的名称,优先级和线程组。

    static void yield()

    对调度程序的一个暗示,即当前线程愿意产生当前使用的处理器。

    主要方法的源码:

    public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
        public void run() {
            if (target != null) {
                target.run();
            }
        }
         public void interrupt() {
            if (this != Thread.currentThread())
                checkAccess();
            synchronized (blockerLock) {
                Interruptible b = blocker;
                if (b != null) {
                    interrupt0();           // Just to set the interrupt flag
                    b.interrupt(this);
                    return;
                }
            }
            interrupt0();
        }
        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);
            }
        }
        public final synchronized void setName(String name) {
            checkAccess();
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
            this.name = name;
            if (threadStatus != 0) {
                setNativeName(name);
            }
        }
        public final synchronized void join(long millis)
        throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
            if (millis == 0) {
                while (isAlive()) {
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }
        public final synchronized void join(long millis, int nanos)
        throws InterruptedException {
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException(
                                    "nanosecond timeout value out of range");
            }
            if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
                millis++;
            }
            join(millis);
        }
        public final void setDaemon(boolean on) {
            checkAccess();
            if (isAlive()) {
                throw new IllegalThreadStateException();
            }
            daemon = on;
        }
        public final void checkAccess() {
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkAccess(this);
            }
        }
        @CallerSensitive
        public ClassLoader getContextClassLoader() {
            if (contextClassLoader == null)
                return null;
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                                       Reflection.getCallerClass());
            }
            return contextClassLoader;
        }
        public void setContextClassLoader(ClassLoader cl) {
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
            }
            contextClassLoader = cl;
        }

    image.gif

    参考资料:

      1. Java 8 中文版 - 在线API中文手册 - 码工具
      相关文章
      |
      7月前
      |
      安全 前端开发 Java
      JDK源码级别彻底剖析JVM类加载机制
      JDK源码级别彻底剖析JVM类加载机制
      |
      7月前
      |
      缓存 Dubbo Java
      趁同事上厕所的时间,看完了 Dubbo SPI 的源码,瞬间觉得 JDK SPI 不香了
      趁同事上厕所的时间,看完了 Dubbo SPI 的源码,瞬间觉得 JDK SPI 不香了
      |
      4月前
      |
      算法 安全 Java
      深入JDK源码:揭开ConcurrentHashMap底层结构的神秘面纱
      【8月更文挑战第24天】`ConcurrentHashMap`是Java并发编程中不可或缺的线程安全哈希表实现。它通过精巧的锁机制和无锁算法显著提升了并发性能。本文首先介绍了早期版本中使用的“段”结构,每个段是一个带有独立锁的小型哈希表,能够减少线程间竞争并支持动态扩容以应对高并发场景。随后探讨了JDK 8的重大改进:取消段的概念,采用更细粒度的锁控制,并引入`Node`等内部类以及CAS操作,有效解决了哈希冲突并实现了高性能的并发访问。这些设计使得`ConcurrentHashMap`成为构建高效多线程应用的强大工具。
      59 2
      |
      设计模式 Java 程序员
      太爆了!阿里最新出品2023版JDK源码学习指南,Github三天已万赞
      最近后台收到很多粉丝私信,说的是程序员究竟要不要去读源码?当下行情,面试什么样的薪资/岗位才会被问到源码? 对此,我的回答是:一定要去读,并且要提到日程上来! 据不完全统计,现在市面上不管是初级,中级,还是高级岗,面试的时候都有可能会问到源码中的问题,它已经成为程序员常规必备的一个技术点。如果你当下想通过一个面试,或者想把中级薪资要到相对于比较高的话,源码这块就必须要会。
      152 0
      |
      6月前
      |
      Java Spring
      深入解析Spring源码,揭示JDK动态代理的工作原理。
      深入解析Spring源码,揭示JDK动态代理的工作原理。
      73 0
      |
      7月前
      |
      设计模式 Java
      根据JDK源码Calendar来看工厂模式和建造者模式
      根据JDK源码Calendar来看工厂模式和建造者模式
      103 3
      |
      7月前
      |
      算法 Java 索引
      【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
      【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
      74 0
      |
      7月前
      |
      消息中间件 Oracle Dubbo
      Netty 源码共读(一)如何阅读JDK下sun包的源码
      Netty 源码共读(一)如何阅读JDK下sun包的源码
      145 1
      |
      7月前
      |
      Java Linux iOS开发
      Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
      Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
      65 0
      |
      7月前
      |
      算法 安全 Java
      ConcurrentLinkedQueue的源码解析(基于JDK1.8)
      ConcurrentLinkedQueue的源码解析(基于JDK1.8) ConcurrentLinkedQueue是Java集合框架中的一种线程安全的队列,它是通过CAS(Compare and Swap)算法实现的并发队列。在并发场景下,ConcurrentLinkedQueue能够保证队列的线程安全性,同时性能也很不错。