前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程基础(二): Thread源码分析

多线程基础(二): Thread源码分析

作者头像
冬天里的懒猫
发布2020-09-08 22:12:16
5360
发布2020-09-08 22:12:16
举报
文章被收录于专栏:做不甩锅的后端

文章目录
  • 1.类结构及其成员变量
    • 1.1 类结构
    • 1.2 成员变量
    • 1.3 常量
  • 2.构造方法
    • 2.1 Thread()
    • 2.2 Thread(Runnable target)
    • 2.3 Thread(Runnable target, AccessControlContext acc)
    • 2.4 Thread(ThreadGroup group, Runnable target)
    • 2.5 Thread(String name)
    • 2.6 Thread(ThreadGroup group, String name)
    • 2.7 Thread(Runnable target, String name)
    • 2.8 Thread(ThreadGroup group, Runnable target, String name)
    • 2.9 Thread(ThreadGroup group, Runnable target, String name,long stackSize)
  • 3. native方法
  • 4.重要的非native方法
    • 4.1 init
    • 4.2 start
    • 4.3 setDaemon
    • 4.4 checkAccess
    • 4.5 join
    • 4.6 sleep
    • 4.7 interrupt
    • 4.8 stop方法
  • 5.内部类
    • 5.1 Caches
    • 5.2 WeakClassKey
    • 5.3 State
  • 6.总结

前面已经对java中Thread的生命周期进行了分析,现在看看Thread的源码。

1.类结构及其成员变量

1.1 类结构

Thread类实现了Runnable,实际上我们说过,需要起一个线程的话,需要继承Thread或者实现Runnable接口。实际上都是实现了Runnable接口。

代码语言:javascript
复制
/**
 * A <i>thread</i> is a thread of execution in a program. The Java
 * Virtual Machine allows an application to have multiple threads of
 * execution running concurrently.
 * <p>
 * Every thread has a priority. Threads with higher priority are
 * executed in preference to threads with lower priority. Each thread
 * may or may not also be marked as a daemon. When code running in
 * some thread creates a new <code>Thread</code> object, the new
 * thread has its priority initially set equal to the priority of the
 * creating thread, and is a daemon thread if and only if the
 * creating thread is a daemon.
 * <p>
 * When a Java Virtual Machine starts up, there is usually a single
 * non-daemon thread (which typically calls the method named
 * <code>main</code> of some designated class). The Java Virtual
 * Machine continues to execute threads until either of the following
 * occurs:
 * <ul>
 * <li>The <code>exit</code> method of class <code>Runtime</code> has been
 *     called and the security manager has permitted the exit operation
 *     to take place.
 * <li>All threads that are not daemon threads have died, either by
 *     returning from the call to the <code>run</code> method or by
 *     throwing an exception that propagates beyond the <code>run</code>
 *     method.
 * </ul>
 * <p>
 * There are two ways to create a new thread of execution. One is to
 * declare a class to be a subclass of <code>Thread</code>. This
 * subclass should override the <code>run</code> method of class
 * <code>Thread</code>. An instance of the subclass can then be
 * allocated and started. For example, a thread that computes primes
 * larger than a stated value could be written as follows:
 * <hr><blockquote><pre>
 *     class PrimeThread extends Thread {
 *         long minPrime;
 *         PrimeThread(long minPrime) {
 *             this.minPrime = minPrime;
 *         }
 *
 *         public void run() {
 *             // compute primes larger than minPrime
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }
 * </pre></blockquote><hr>
 * <p>
 * The following code would then create a thread and start it running:
 * <blockquote><pre>
 *     PrimeThread p = new PrimeThread(143);
 *     p.start();
 * </pre></blockquote>
 * <p>
 * The other way to create a thread is to declare a class that
 * implements the <code>Runnable</code> interface. That class then
 * implements the <code>run</code> method. An instance of the class can
 * then be allocated, passed as an argument when creating
 * <code>Thread</code>, and started. The same example in this other
 * style looks like the following:
 * <hr><blockquote><pre>
 *     class PrimeRun implements Runnable {
 *         long minPrime;
 *         PrimeRun(long minPrime) {
 *             this.minPrime = minPrime;
 *         }
 *
 *         public void run() {
 *             // compute primes larger than minPrime
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }
 * </pre></blockquote><hr>
 * <p>
 * The following code would then create a thread and start it running:
 * <blockquote><pre>
 *     PrimeRun p = new PrimeRun(143);
 *     new Thread(p).start();
 * </pre></blockquote>
 * <p>
 * Every thread has a name for identification purposes. More than
 * one thread may have the same name. If a name is not specified when
 * a thread is created, a new name is generated for it.
 * <p>
 * Unless otherwise noted, passing a {@code null} argument to a constructor
 * or method in this class will cause a {@link NullPointerException} to be
 * thrown.
 *
 * @author  unascribed
 * @see     Runnable
 * @see     Runtime#exit(int)
 * @see     #run()
 * @see     #stop()
 * @since   JDK1.0
 */
public
class Thread implements Runnable {
    
}

如上是Thread的源码。 其注释大意为:thread是程序中执行的线程,JVM允许在一个程序中分配多个线程并发执行。 每个线程都有一个优先级,具有较高优先级的线程优先于优先级较低的线程执行,每个线程也可以标记为守护线程,也可以不标记为守护线程。当运行在某个线程中的代码创建一个新的线程的对象时,新的线程优先级最初设置为与创建的线程的优先级相等。当且仅当创建线程是守护线程的时候,被创建的新线程才是守护线程。 当jvm启动的时候,通常有一个单独的非守护线程,通常用调用main方法所在的类命名。java虚拟机会继续执行线程,直到出现如下情况:

  • 运行时Runtime调用exit方法,安全管理器允许执行退出操作。
  • 所有不是守护线程的线程都died,要么从调用run的方法返回,要么抛出一个传播到run方法之外的异常。

通常有两种方式创建一个线程,一种是继承Thread类,子类应该重写run方法。然后子类的实例是可分配的并启动。例如,计算质数的线程大于指定值可写成:

代码语言:javascript
复制
class PrimeThread extends Thread {
    long minPrime;
    PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }

   public void run() {
        // compute primes larger than minPrime
       &nbsp;.&nbsp;.&nbsp;.
     }
}

然后通过如下代码来创建线程:

代码语言:javascript
复制
PrimeThread p = new PrimeThread(143);
p.start();

创建线程的另外一种方法是申明一个类实现Runnable接口。然后这个类实现run方法。类的实例在此后分配,在创建时做为Thread的参数传递给Thread,然后启动,看起来如下所示:

代码语言:javascript
复制
class PrimeRun implements Runnable {
   long minPrime;
   PrimeRun(long minPrime) {
       this.minPrime = minPrime;
   }

  public void run() {
       // compute primes larger than minPrime
       &nbsp;.&nbsp;.&nbsp;.
   }
}

之后通过如下代码创建:

代码语言:javascript
复制
PrimeRun p = new PrimeRun(143);
 new Thread(p).start();

每个线程都有一个用于标识的名称,超过一个线程可以有相同的名字,如果名称未指定时创建要给线程,将自动为其生成一个新名称。

1.2 成员变量

其常量区代码如下:

代码语言:javascript
复制
private volatile String name;
private int            priority;
private Thread         threadQ;
private long           eetop;

/* Whether or not to single_step this thread. */
private boolean     single_step;

/* Whether or not the thread is a daemon thread. */
private boolean     daemon = false;

/* JVM state */
private boolean     stillborn = false;

/* What will be run. */
private Runnable target;

/* The group of this thread */
private ThreadGroup group;

/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;

/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;

/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

/*
 * InheritableThreadLocal values pertaining to this thread. This map is
 * maintained by the InheritableThreadLocal class.
 */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

/*
 * The requested stack size for this thread, or 0 if the creator did
 * not specify a stack size.  It is up to the VM to do whatever it
 * likes with this number; some VMs will ignore it.
 */
private long stackSize;

/*
 * JVM-private state that persists after native thread termination.
 */
private long nativeParkEventPointer;

/*
 * Thread ID
 */
private long tid;

/* For generating thread ID */
private static long threadSeqNumber;

/* Java thread status for tools,
 * initialized to indicate thread 'not yet started'
 */

private volatile int threadStatus = 0;


private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
}

/**
 * The argument supplied to the current call to
 * java.util.concurrent.locks.LockSupport.park.
 * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
 * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
 */
volatile Object parkBlocker;

/* The object in which this thread is blocked in an interruptible I/O
 * operation, if any.  The blocker's interrupt method should be invoked
 * after setting this thread's interrupt status.
 */
private volatile Interruptible blocker;

其主要成员变量如下:

变量名

类型

说明

name

volatile String

线程名称

priority

int

线程的优先级,默认为5,范围1-10

threadQ

Thread

eetop

long

single_step

boolean

是否单步执行

daemon

boolean

守护线程状态,默认为false

stillborn

boolean

JVM状态,默认为false

target

target

将被执行的Runnable实现类

group

ThreadGroup

当前线程的线程组

contextClassLoader

ClassLoader

这个线程上下文的类加载器

inheritedAccessControlContext

AccessControlContext

该线程继承的AccessControlContext

threadInitNumber

static int

用于匿名线程的自动编号

threadLocals

ThreadLocal.ThreadLocalMap

属于此线程的ThreadLocal,这个映射关系通过ThreadLocal维持

inheritableThreadLocals

ThreadLocal.ThreadLocalMap

这个线程的InheritableThreadLocal,其映射关系通过InheritableThreadLocal维持

stackSize

long

此线程的请求的堆栈的大小,如果创建者的请求堆栈大小为0,则不指定堆栈大小,由jvm来自行决定。一些jvm会忽略这个参数。

nativeParkEventPointer

long

在本机线程终止后持续存在的jvm私有状态。

tid

long

线程的ID

threadSeqNumber

static long

用于生成线程的ID

threadStatus

volatile int

java线程状态,0表示未启动

parkBlocker

volatile Object

提供给LockSupport调用的参数

blocker

volatile Interruptible

此线程在可中断的IO操作中被阻塞的对象,阻塞程序的中断方法应该在设置了这个线程中断状态之后被调用

1.3 常量

代码语言:javascript
复制
/**
 * 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;

实际上这些常量值是对于线程优先级的常量,最小为1,最大为10,默认值为5。操作系统在线程在运行的过程中会按照优先级来分配时间片。

2.构造方法

2.1 Thread()

空构造函数,发呢配一个新的Thread对象,实际上是调用的init方法。由于Thread大部分代码都是native来实现,因此这个构造函数是通过改变前面的成员变量来实现对Thread各种行为的改变。

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, null, gname)}, where {@code gname} is a newly generated
 * name. Automatically generated names are of the form
 * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
 */
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

2.2 Thread(Runnable target)

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, target, gname)}, where {@code gname} is a newly generated
 * name. Automatically generated names are of the form
 * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
 *
 * @param  target
 *         the object whose {@code run} method is invoked when this thread
 *         is started. If {@code null}, this classes {@code run} method does
 *         nothing.
 */
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

此方法是我们通常用Runnable启动线程的方法。 实际上我们穿入的Runnable对象,被放置在了target变量中,之后通过后jvm中启动线程|

2.3 Thread(Runnable target, AccessControlContext acc)

代码语言:javascript
复制
/**
 * Creates a new Thread that inherits the given AccessControlContext.
 * This is not a public constructor.
 */
Thread(Runnable target, AccessControlContext acc) {
    init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}

在传入Runnable的时候还可以指定AccessControlContext。

2.4 Thread(ThreadGroup group, Runnable target)

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (group, target, gname)} ,where {@code gname} is a newly generated
 * name. Automatically generated names are of the form
 * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
 *
 * @param  group
 *         the thread group. If {@code null} and there is a security
 *         manager, the group is determined by {@linkplain
 *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
 *         If there is not a security manager or {@code
 *         SecurityManager.getThreadGroup()} returns {@code null}, the group
 *         is set to the current thread's thread group.
 *
 * @param  target
 *         the object whose {@code run} method is invoked when this thread
 *         is started. If {@code null}, this thread's run method is invoked.
 *
 * @throws  SecurityException
 *          if the current thread cannot create a thread in the specified
 *          thread group
 */
public Thread(ThreadGroup group, Runnable target) {
    init(group, target, "Thread-" + nextThreadNum(), 0);
}

使用线程组ThreadGroup。如果有安全管理器,则线程由安全管理器返回 SecurityManager.getThreadGroup()。如果没有安全管理器或者SecurityManager.getThreadGroup()返回为空,则返回当前的线程组。

2.5 Thread(String name)

指定线程的名称:

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, null, name)}.
 *
 * @param   name
 *          the name of the new thread
 */
public Thread(String name) {
    init(null, null, name, 0);
}

2.6 Thread(ThreadGroup group, String name)

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (group, null, name)}.
 *
 * @param  group
 *         the thread group. If {@code null} and there is a security
 *         manager, the group is determined by {@linkplain
 *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
 *         If there is not a security manager or {@code
 *         SecurityManager.getThreadGroup()} returns {@code null}, the group
 *         is set to the current thread's thread group.
 *
 * @param  name
 *         the name of the new thread
 *
 * @throws  SecurityException
 *          if the current thread cannot create a thread in the specified
 *          thread group
 */
public Thread(ThreadGroup group, String name) {
    init(group, null, name, 0);
}

2.7 Thread(Runnable target, String name)

代码语言:javascript
复制
/**
 * Allocates a new {@code Thread} object. This constructor has the same
 * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
 * {@code (null, target, name)}.
 *
 * @param  target
 *         the object whose {@code run} method is invoked when this thread
 *         is started. If {@code null}, this thread's run method is invoked.
 *
 * @param  name
 *         the name of the new thread
 */
public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}

通过Runnable并指定线程的name。

2.8 Thread(ThreadGroup group, Runnable target, String name)

代码语言:javascript
复制
public Thread(ThreadGroup group, Runnable target, String name) {
    init(group, target, name, 0);
}

2.9 Thread(ThreadGroup group, Runnable target, String name,long stackSize)

代码语言:javascript
复制
public Thread(ThreadGroup group, Runnable target, String name,
              long stackSize) {
    init(group, target, name, stackSize);
}

分配一个线程,使其将target做为目标对象,具有name指定的名称,和group指定的线程组。其中,指定StackSize参数能够决定其for循环栈的深度,但是这也由JVM决定,某些JVM这个参数并不能生效。 JVM可以自由的处理stackSize的参数做为建议值,如果指定的值低得不合理,那么可以使用jvm平台的最小值。如果值太高,则可能会使用平台缺省的最大值。虚拟机可以自由地四舍五入指定的值,让到JVM认为是合适的值。 stackSize参数为0则会导致其与Thread(ThreadGroup, Runnable, String)构造器完全一致。 由于这个特性依赖于JVM平台,因此在使用的时候要特别小心,给定线程的stackSize可能因为线程对峙的大小造成不同JRE实现有所不同。鉴于此,可能需要仔细调整堆栈的大小参数,根据JRE要运行程序的实际情况进行调优。

3. native方法

由于Thread大部分逻辑都是由JVM完成,因此核心的方法都是native方法。

代码语言:javascript
复制
//确保registerNatives是<clinit>做的第一件事,这个代码要放在代码的最前面。
private static native void registerNatives();

//返回当前线程
public static native Thread currentThread();

//当前线程在获取CPU执行权之后,让出,之后让等待队列的线程重新竞争。有可能是当前线程再次抢到执行权,也有可能是其他线程。
public static native void yield();

//休眠
public static native void sleep(long millis) throws InterruptedException;

//启动
private native void start0();

//测试某个值是否被中断 中断状态根据传入的ClearInterrupted值进行重置
private native boolean isInterrupted(boolean ClearInterrupted);

//测试线程是否是存活状态
public final native boolean isAlive();

//计算线程中的堆栈数,此线程必须被暂停 ,这个方法已不再建议使用
public native int countStackFrames();


//当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
public static native boolean holdsLock(Object obj);

//导出线程堆栈信息
private native static StackTraceElement[][] dumpThreads(Thread[] threads);

//get线程
private native static Thread[] getThreads();

//设置优先级
private native void setPriority0(int newPriority);
//停止
private native void stop0(Object o);
//挂起
private native void suspend0();
//重置
private native void resume0();
//中断
private native void interrupt0();
//设置线程名称
private native void setNativeName(String name);

4.重要的非native方法

4.1 init

线程初始化方法

代码语言:javascript
复制
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
   //name如果为空,则返回异常,实际上name在其他方法中如果不指定会自动生成,通常为"Thread-" + nextThreadNum()
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;
    //指定父线程
    Thread parent = currentThread();
    //安全管理器
    SecurityManager security = System.getSecurityManager();
    //如果线程组为null
    if (g == null) {
        /* Determine if it's an applet or not */

        /* If there is a security manager, ask the security manager
           what to do. */
        if (security != null) {
            g = security.getThreadGroup();
        }

        /* If the security doesn't have a strong opinion of the matter
           use the parent thread group. */
        if (g == null) {
        //线程组为空的话,g为parent的线程组
            g = parent.getThreadGroup();
        }
    }

    /* checkAccess regardless of whether or not threadgroup is
       explicitly passed in. */
    g.checkAccess();

    /*
     * Do we have the required permissions?
     */
     //如果安全管理器为空
    if (security != null) {
        if (isCCLOverridden(getClass())) {
            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
    }

    g.addUnstarted();

    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;
    this.inheritedAccessControlContext =
            acc != null ? acc : AccessController.getContext();
    this.target = target;
    setPriority(priority);
    if (inheritThreadLocals && parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    /* Stash the specified stack size in case the VM cares */
    //指定stackSize
    this.stackSize = stackSize;

    /* Set thread ID */
    //指定线程id
    tid = nextThreadID();
}

4.2 start

线程启动的方法:

代码语言:javascript
复制
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 {
    //实际上调用的native方法
    start0();
    //之后修改start的状态
    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 */
    }
}
}

4.3 setDaemon

设置守护线程状态:

代码语言:javascript
复制
public final void setDaemon(boolean on) {
    checkAccess();
    if (isAlive()) {
        throw new IllegalThreadStateException();
    }
    daemon = on;
}

4.4 checkAccess

检查访问状态:

代码语言:javascript
复制
public final void checkAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkAccess(this);
    }
}

4.5 join

join将当前运行的线程阻塞,之后让join的持有线程执行完之后再继续执行。等待时间为传入的参数。

代码语言:javascript
复制
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) {
    //如果当前线程可用,则调用wait
        while (isAlive()) {
            wait(0);
        }
    } else {
        通过wait方法delay。
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

这个方法提供给另外两个方法调用:

代码语言:javascript
复制
 public final synchronized void join(long millis, int nanos) throws InterruptedException;
 public final void join() throws InterruptedException;

其中wait(0)的话,则会一直阻塞,直到notify才会返回。不难发现,join方法底层实际上是wait方法。

4.6 sleep

sleep方法通过native方法实现。

代码语言:javascript
复制
public static void sleep(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++;
    }

    sleep(millis);
}

其中只是判断了值的范围。

4.7 interrupt

代码语言:javascript
复制
public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();
   锁定之后调用interrupt0
    synchronized (blockerLock) {
        Interruptible b = blocker;
        //如果b不为null则返回
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    //当b为空的情况确保interrupt0一定会被执行。
    interrupt0();
}

4.8 stop方法

stop方法已经过时,不再采用这个方法停止线程,这是因为,stop方法非常粗暴,会导致很多问题,后面详细分析。

代码语言:javascript
复制
@Deprecated
public final void stop() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        checkAccess();
        if (this != Thread.currentThread()) {
            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
        }
    }
    // A zero status value corresponds to "NEW", it can't change to
    // not-NEW because we hold the lock.
    if (threadStatus != 0) {
        resume(); // Wake up thread if it was suspended; no-op otherwise
    }

    // The VM can handle all thread states
    stop0(new ThreadDeath());
}

5.内部类

5.1 Caches

cache缓存了子类安全审计的结果。如果未来要进行使用,采用ConcurrentReferenceHashMap替换。

代码语言:javascript
复制
/** cache of subclass security audit results */
/* Replace with ConcurrentReferenceHashMap when/if it appears in a future
 * release */
private static class Caches {
    //缓存子类安全审计结果
    /** cache of subclass security audit results */
    static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
        new ConcurrentHashMap<>();

    //对审计子类的weak引用进行排队
    /** queue for WeakReferences to audited subclasses */
    static final ReferenceQueue<Class<?>> subclassAuditsQueue =
        new ReferenceQueue<>();
}

5.2 WeakClassKey

弱引用对象的key。

代码语言:javascript
复制
/**
 *  Weak key for Class objects.
 **/
static class WeakClassKey extends WeakReference<Class<?>> {
    /**
     * saved value of the referent's identity hash code, to maintain
     * a consistent hash code after the referent has been cleared
     */
    private final int hash;

    /**
     * Create a new WeakClassKey to the given object, registered
     * with a queue.
     */
    WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
        super(cl, refQueue);
        hash = System.identityHashCode(cl);
    }

    /**
     * Returns the identity hash code of the original referent.
     */
    @Override
    public int hashCode() {
        return hash;
    }

    /**
     * Returns true if the given object is this identical
     * WeakClassKey instance, or, if this object's referent has not
     * been cleared, if the given object is another WeakClassKey
     * instance with the identical non-null referent as this one.
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;

        if (obj instanceof WeakClassKey) {
            Object referent = get();
            return (referent != null) &&
                   (referent == ((WeakClassKey) obj).get());
        } else {
            return false;
        }
    }
}

5.3 State

线程的状态内部枚举类。这个线程的状态有NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED状态。

代码语言:javascript
复制
public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,

    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     */
    WAITING,

    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,

    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     */
    TERMINATED;
}

状态的详细描述在前面文章中已经详细介绍。我们重点需要关注这些状态的转换:

6.总结

本文分析了Thread的源码。我们可以看出,实际上join方法实际上底层是采用了synchronized和Object的wait方法。另外,停止线程的stop方法已经弃用,我们应该用interrupt()方法。 stop和interrupt方法区别在于: stop方法会立即杀死线程,不给线程任何暂停的机会,一旦线程持有Lock,那么线程就来不及调用unlock方法,这样就导致其他线程再也不可能获得这个锁。这是非常危险的操作,也是为什么stop方法会被弃用的原因。 interrupt方法则仅仅只是通知线程,线程可以继续执行后续操作,interrupt实际上是一个异常检测的流程。当线程 处于 WAITING、TIMED_WAITING 状态时,如果其他线程调用线程的 interrupt() 方法,会使线程返回到 RUNNABLE 状态,同时线程 的代码会触发 InterruptedException 异常。 此外还有一种主动检测机制,就是通过调用isInterrupted()方法。 最后,我们需要重点掌握线程模型中的6个状态及其转换的过程。这也是我们学习线程的重点。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 1.类结构及其成员变量
    • 1.1 类结构
      • 1.2 成员变量
        • 1.3 常量
        • 2.构造方法
          • 2.1 Thread()
            • 2.2 Thread(Runnable target)
              • 2.3 Thread(Runnable target, AccessControlContext acc)
                • 2.4 Thread(ThreadGroup group, Runnable target)
                  • 2.5 Thread(String name)
                    • 2.6 Thread(ThreadGroup group, String name)
                      • 2.7 Thread(Runnable target, String name)
                        • 2.8 Thread(ThreadGroup group, Runnable target, String name)
                          • 2.9 Thread(ThreadGroup group, Runnable target, String name,long stackSize)
                          • 3. native方法
                          • 4.重要的非native方法
                            • 4.1 init
                              • 4.2 start
                                • 4.3 setDaemon
                                  • 4.4 checkAccess
                                    • 4.5 join
                                      • 4.6 sleep
                                        • 4.7 interrupt
                                          • 4.8 stop方法
                                          • 5.内部类
                                            • 5.1 Caches
                                              • 5.2 WeakClassKey
                                                • 5.3 State
                                                • 6.总结
                                                领券
                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档