java-高并发-解读Thread类

概述
线程是程序中的一个执行线程。java虚拟机允许应用程序具有多个线程执行并发运行。
每个线程都有优先权。优先级较高的线程优先于优先级较低的线程执行。
每个线程可能或可能不被标记为守护进程。

当代码运行时一些线程创建一个新的Thread对象,新的线程的优先级最初设置等于
它的创建线程,当创建线程是一个守护线程,它也是守护线程

当一个java虚拟机启动时,通常有一个单一的非守护进程线程(通常调用名为某些指定类的main
java虚拟机器继续执行线程,直到以下任一个发生:
1、Runtime的exit方法以及被调用 并且安全管理器允许退出操作发生。
2、不是守护线程线程的所有线程都已死亡,从调用返回到run方法或通过抛出传播超出run方法的异常。

有两种方法来创建一个新的执行线程。
一是
将类声明为Thread的子类。这个
*子类应该重写类的Runnable方法
然后子类的实例可以是分配和启动。

例如,一个计算素数大于规定值的线程可写如下:

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

*下面的代码将创建一个线程并开始运行它:

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

*创建线程的另一种方法是声明一个类实现<代码> Runnaby<代码>接口。
*然后被分配,在创建时作为参数传递

那个类实现runnable方法。当创建并启动线程时,类的一个实例被分配,并作为参数传递

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

*下面的代码将创建一个线程并开始运行它:

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

*每个线程都有用于标识目的的名称。
不止一个线程可能具有相同的名称。如果未指定名称时创建一个线程,为它生成一个新名称。
*除非另有说明,将{@代码null }参数传递给构造函数。或该类中的方法将导致NullPointerException


方法

提示当前线程愿意让出 它当前处理的使用权。调度器可以忽略这个提示。

在线程之间让步是改善相对处理的启发式尝试,否则将过度利用CPU。其使用应结合详细的分析和基准测试确保它实际上具有预期的效果。

使用这种方法很少合适。也许可以用于调试或测试目的,在那里可能有助于重现由于竞争条件而出现的bug。在设计并发控制结构时也可能有用。例如{@link java.util.concurrent.locks} package

 public static native void yield();

在执行指定的毫秒数范围内,使当前正在执行的线程休眠(暂时停止),服从系统定时器和调度器的精度和准确性。线程不会失去任何监视器的所有权。
如果任何线程中断了当前线程。这个当前线程中断的状态将在抛出异常时清除。

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

用当前AccessControlContext初始化线程。

 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }

初始化一个线程。

    / * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     */
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        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.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 (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

分配一个新的线程对象,

 public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

分配一个新的Thread对象,使其具有Target作为其运行对象,具有指定的name作为其名称,属于group引用的线程组。如果有一个安全管理器,{SecurityManager}检查访问(ThreadGroup)checkAccess }方法以线程组作为参数来调用。

另外,它的checkPermission()方法被调用带有
RuntimePermission(“enableContextClassLoaderOverride”权限
由重写getContextClassLoader或者setContextClassLoader的子类构造函数直接或间接调用

新创建的线程的优先级设置为等于创建线程的优先级,即当前运行的线程。该方法setPriority 可能是
用于将优先级更改为新值。

当且仅当创建线程的当前线程被标记作为守护进程线程时,新创建的线程最初被标记为守护线程,setDaemon可以用来改变线程是否是守护进程。

  public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

导致该线程开始执行的java虚拟机调用该线程的run方法。
结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行它的run方法)
启动线程不止一次是不合法的,特别是,线程一旦完成执行,就不能重新启动。

 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 */
            }
        }
    }

该方法由系统调用以给出线程在实际退出之前清理一次机会。

 private void exit() {
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        target = null;
        /* Speed the release of some of these resources */
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }

中断此线程

除非,通过调用线程checkAccess()对象 允许当前线程中断它自身,否则抛出SecurityException

如果线程在调用wait()方法、或者Object的等待方法或者join sleep方法时阻塞
它的中断状态将被清除或者抛出InterruptedException

如果线程阻塞在IO操作InterruptibleChannel
然后这个通道将被关闭,线程中断状态将被设置,线程将接收一个ClosedByInterruptException

如果线程阻塞在一个selector 然后这个线程的中断状态将被设置
或者他立即从select操作中返回,可能是以非零值,仅当Selector wakeup方法被调用

如果前面的条件没有一个,那么这个线程中断状态将被设置。

中断不是活着的线程不会产生任何效果

 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();
    }

测试当前线程是否已中断。这个
通过该方法清除线程的*中断状态。在换句话说,如果这种方法被连续调用两次,
第二次调用将返回false(除非当前线程又被中断,在他的第一次调用已经清楚它的中断状态 并且在第二次调用之前检查它
)。

一个线程中断将会被忽略 因为一个线程不在中断的时间存活 将被这个方法返回false反映

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

在该线程中最多等待millis毫秒死亡。0的超时意味着永远等待。
通过循环调用wait 基于isAlive方法
当一个线程终止,notifyAll方法将被调用
建议不要使用wait notify 或者notifyAll在线程实例

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;
            }
        }
    }

返回此线程的上下文类加载器。语境ClassLoader由线程的创建者提供使用。
在加载类和资源时,在该线程中运行代码。

如果不是setContextClassLoader 集合,则默认为父线程的类加载器上下文。这个上下文类加载器
原始线程通常被设置为用于加载应用程序。

 @CallerSensitive
    public ClassLoader getContextClassLoader() {
        if (contextClassLoader == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                                   Reflection.getCallerClass());
        }
        return contextClassLoader;
    }

猜你喜欢

转载自blog.csdn.net/qq_16038125/article/details/80332431