多线程1——Thread和Runnable

多线程1——Thread和Runnable


Thread

创建线程的方法:

//1.继承Thread
class MyThread extends Thread{

    @override
    public void run(){
        for(int I=0;i<100; I++){
            System.out.println(i);
        }
    }
}

MyThread myThread = new MyThread();
myThread.start();

//2.实现Runnable
class MyTask implements Runnable{
    @override
    public void run(){
        for(int I=0;i<100; I++){
            System.out.println(i);
        }
    }
}
new Thread(new MyTask()).start();

这是两种创建多线程的方法。个人跟喜欢称其为两种创建任务提交任务给线程进行执行的方法。

参考C++中创建线程的一种方法:

uintptr_t _beginthreadex( // NATIVE CODE  
   void *security,  //线程安全属性
   unsigned stack_size,  //线程的栈大小
   unsigned ( *start_address )( void * ),//线程函数  
   void *arglist,  //传递到线程函数中的参数
   unsigned initflag,  //线程初始化标记
   unsigned *thrdaddr   //线程ID
);
#include "stdafx.h"
#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;

//C++中创建线程的方法是:首先创建一个线程的主入口函数,在主入口函数中执行任务
//之后使用_beginthreadex创建线程,该线程所需执行的任务是ThreadProc
unsigned int _stdcall ThreadProc(LPVOID lpParameter)
{
    cout << "thread function ThreadProc!\n";
    return 0;
}

int main()
{
    _beginthreadex(NULL, 0, ThreadProc, 0, 0, NULL);

    Sleep(1000);
    cout << "main end!\n";
    system("pause");
    return 0;
}

C++中创建线程的方法是:首先创建一个函数A,在函数中执行任务。之后A作为参数使用_beginthreadex创建线程,该线程所需执行的任务是A。
同样,java中也是如此。在实现Runnable或者在继承Thread中重写run方法,既是提供执行任务的函数。之后实例化Thread,调用start()函数,就是分配一个线程,在该线程中运行run方法,执行任务。

两种创建线程的方法更倾向于使用第二种。因为其对于理解任务和提交任务给线程比较容易。

每当看到下面这种形式的代码时: new Thread(runnable).start()
并且你希望获得一种更加灵活的执行策略时,请考虑使用Excutor来代替
引用自《Java并发编程实战》

Runable

@FunctionalInterface
public interface Runnable {
   /**
   当一个实现了Runnable接口的类被传递到一个线程的时候,启动线程后,线程将会调用run方法
   */
    public abstract void run();
}

Thread

Thread方法实现了Runnable接口。
我们通常接触的Thread类的方法以下这几种。

  • start()和run()
  • sleep()
  • suspend() 和 resume()
  • stop()
  • interrupted()
  • yield()
  • join()
  • set(Default)UncaughtExceptionHandler()

    start()和run()

//run方法就是我们在继承Thread的时候需要重写的方法。

/**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *启动一个线程,并在线程中执行run方法。
     一个线程只能启动一次,再次启动会抛出IllegalThreadStateException
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    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".
         * 这种启动线程的方法并不是VM启动main线程或者system线程的方法
         */
        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 native void start0();

这是启动线程的start()方法。我们能从中注意到的点是:

  • 一个线程只能启动一次,在start()方法中通过线程的状态来判断线程是否已经被启动。线程启动后将执行run方法。
  • start()方法是一个同步的方法。防止同时启动多个线程的情况。

但是start0()方法是一个本地方法。在Thread类中有很多方法都是本地方法。

sleep()方法

    //
     /*
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     //让一个正在执行的线程休眠一定的时间。在休眠期间线程不释放其拥有的锁。
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.  
     *          当sleep的线程被中断,则抛出InterruptedException
     */

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

    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds plus the specified
     * number of nanoseconds, subject to the precision and accuracy of system
     * timers and schedulers. The thread does not lose ownership of any
     * monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to sleep
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value of
     *          {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     **/
    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);
    }

sleep()方法又是本地方法。有两点:

  • 调用Sleep()意味使当前线程休眠。
public void test(){
    MyTask task = new MyTask();
    Thread myThread = new MyThread(task);
    myThread.start();
    myThread.sleep(5000);
    Thread.sleep(5000);//两者的所用一致,都是使当前线程休眠5秒钟,而不是让myThread休眠5秒。
}
  • 当前线程被休眠后,状态从RUNNABLE变成TIMED_WAITING.处于TIMED_WAITING状态的线程如果被中断则会抛出InterruptedException。另外处于被中断状态的线程如果调用sleep,也会抛出InterruptedException

    suspend()和resume()

    suspend和resume的方法体都比较简单。

    /**
     * Suspends this thread.
     * <p>
     * First, the <code>checkAccess</code> method of this thread is called
     * with no arguments. This may result in throwing a
     * <code>SecurityException </code>(in the current thread).
     * <p>
     * If the thread is alive, it is suspended and makes no further
     * progress unless and until it is resumed.
     * 挂起线程。首先使用checkAccess来检查当前线程是否可以更改这个线程。
     * 在thread的源码中经常看到两个单词,一个是current thread,一个是this thread。
     * myThread.suspend()
     * 调用myThread.suspend()这句话的线程为当前线程。myThread为this thread。
     * 如果checkAccess不抛出异常,则线程会一直暂停直到resume()方法被调用
     * @exception  SecurityException  if the current thread cannot modify
     *               this thread.
     * @see #checkAccess
     * @deprecated   This method has been deprecated, as it is
     *   inherently deadlock-prone.  If the target thread holds a lock on the
     *   monitor protecting a critical system resource when it is suspended, no
     *   thread can access this resource until the target thread is resumed. If
     *   the thread that would resume the target thread attempts to lock this
     *   monitor prior to calling <code>resume</code>, deadlock results.  Such
     *   deadlocks typically manifest themselves as "frozen" processes.
     *   For more information, see
     *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     * 这个方法是被废弃的。一个线程被暂停之后不会释放所拥有的锁。因此其他需要资源的线程将一直阻塞。另外如果一个线程必须持有锁才能调用resume来恢复该线程的运行,这就会造成死锁。
     * 
     */
    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }

    /**
     * Resumes a suspended thread.
     * <p>
     * First, the <code>checkAccess</code> method of this thread is called
     * with no arguments. This may result in throwing a
     * <code>SecurityException</code> (in the current thread).
     * <p>
     * If the thread is alive but suspended, it is resumed and is
     * permitted to make progress in its execution.
     * 恢复一个被暂停的线程。
     * @exception  SecurityException  if the current thread cannot modify this
     *               thread.
     * @see        #checkAccess
     * @see        #suspend()
     * @deprecated This method exists solely for use with {@link #suspend},
     *     which has been deprecated because it is deadlock-prone.
     *     For more information, see
     *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @Deprecated
    public final void resume() {
        checkAccess();
        resume0();
    }

suspend()和resume()方法是一对被废弃的方法。

  • 在suspend()后,线程持有的锁不被释放,容易遭成死锁,饥饿。死锁的原因上面已经解释过。当线程由于无法访问它所需要的资源而不能继续执行的时候,就发生了“饥饿”。一个线程持有锁A被暂停,其他需要锁A的线程则被阻塞。
  • suspend()的时候,可能会造成数据处于不一致的状态

如果suspend和resume不能用,那么应该使用什么机制来实现线程的暂停和恢复呢?
wait和notify

stop()方法


/**
     * Forces the thread to stop executing.
     * 强行终止一个线程
     * <p>
     * If there is a security manager installed, its <code>checkAccess</code>
     * method is called with <code>this</code>
     * as its argument. This may result in a
     * <code>SecurityException</code> being raised (in the current thread).
     * <p>
     * If this thread is different from the current thread (that is, the current
     * thread is trying to stop a thread other than itself), the
     * security manager's <code>checkPermission</code> method (with a
     * <code>RuntimePermission("stopThread")</code> argument) is called in
     * addition.
     * Again, this may result in throwing a
     * <code>SecurityException</code> (in the current thread).
     * 终止线程前需要对安全机制进行检查。这一步没有了解。
     * <p>
     * The thread represented by this thread is forced to stop whatever
     * it is doing abnormally and to throw a newly created
     * <code>ThreadDeath</code> object as an exception.
     * <p>
     * 线程会被强行终止,不管它在做什么,而且会抛出一个ThreadDeath的异常。
     * It is permitted to stop a thread that has not yet been started.
     * If the thread is eventually started, it immediately terminates.
     * <p>
     * 也允许终止一个还没有启动的线程。
     * An application should not normally try to catch
     * <code>ThreadDeath</code> unless it must do some extraordinary
     * cleanup operation (note that the throwing of
     * <code>ThreadDeath</code> causes <code>finally</code> clauses of
     * <code>try</code> statements to be executed before the thread
     * officially dies).  If a <code>catch</code> clause catches a
     * <code>ThreadDeath</code> object, it is important to rethrow the
     * object so that the thread actually dies.
     * 一个应用不应该尝试捕捉ThreadDeath,除非它必须做些清理的工。ThreadDeath的抛出会导致finnally语句块在线程正式终止前执行。
     * <p>
     * The top-level error handler that reacts to otherwise uncaught
     * exceptions does not print out a message or otherwise notify the
     * application if the uncaught exception is an instance of
     * <code>ThreadDeath</code>.
     *一个顶级的错误处理器,当抛出的异常时ThreadDeath的实例的时候,会通知应用程序。否则不会打印出异常信息
     * @exception  SecurityException  if the current thread cannot
     *               modify this thread.
     * @see        #interrupt()
     * @see        #checkAccess()
     * @see        #run()
     * @see        #start()
     * @see        ThreadDeath
     * @see        ThreadGroup#uncaughtException(Thread,Throwable)
     * @see        SecurityManager#checkAccess(Thread)
     * @see        SecurityManager#checkPermission
     * @deprecated This method is inherently unsafe.  Stopping a thread with
     *       Thread.stop causes it to unlock all of the monitors that it
     *       has locked (as a natural consequence of the unchecked
     *       <code>ThreadDeath</code> exception propagating up the stack).  If
     *       any of the objects previously protected by these monitors were in
     *       an inconsistent state, the damaged objects become visible to
     *       other threads, potentially resulting in arbitrary behavior.  Many
     *       uses of <code>stop</code> should be replaced by code that simply
     *       modifies some variable to indicate that the target thread should
     *       stop running.  The target thread should check this variable
     *       regularly, and return from its run method in an orderly fashion
     *       if the variable indicates that it is to stop running.  If the
     *       target thread waits for long periods (on a condition variable,
     *       for example), the <code>interrupt</code> method should be used to
     *       interrupt the wait.
     *       For more information, see
     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     * 这个方法不是安全的,因此被废弃。一个线程stop之后会释放其拥有的所有锁。有可能会导致被锁保护的共享状态变量出现不一致的状态。而其他的线程将会读取到不符合不变性条件的共享数据。抛去stop方法,我们应该使用一个状态变量来指示一个线程是否应该被终止。目标线程应该有规律的检查这个状态变量,并在需要停止的时候停止。如果目标线程处于等待状态,则应该使用interrupt方法在中断等待状态。
     */
    @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());
    }

    /**
     * Throws {@code UnsupportedOperationException}.
     *
     * @param obj ignored
     *
     * @deprecated This method was originally designed to force a thread to stop
     *        and throw a given {@code Throwable} as an exception. It was
     *        inherently unsafe (see {@link #stop()} for details), and furthermore
     *        could be used to generate exceptions that the target thread was
     *        not prepared to handle.
     *        For more information, see
     *        <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *        are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @Deprecated
    public final synchronized void stop(Throwable obj) {
        throw new UnsupportedOperationException();
    }

stop方法也是被放弃的方法,那我们应该采用什么机制来停止一个线程呢
1.设置一个“请求停止标志”,让目标线程轮循该变量。
2.使用中断
在停止一个方法的同时又什么需要注意的事项吗?
如何取消不支持中断的阻塞方法?什么是不支持中断的阻塞方法?
如何取消线程池中的任务?(我们没有办法拿到具体执行任务的线程)

interrupt()

/**
     * Interrupts this thread.
     * 中断线程
     * 1.安全检查
     * 2.因为调用object的wait(),wait(long),wait(long,int),或者thread类的join(),join(long),join(long,int),sleep(long),sleep(long,int)方法
     * 线程被阻塞,则线程的中断状态被清除,且抛出InterruptedException异常
     * 3.如果线程因为java.nio.channels.InterruptibleChannel上的一个IO操作而被阻塞,则调用interrupt()会使channel关闭,线程的中断状态被设置,并且线程接收到java.nio.channels.ClosedByInterruptException异常
     * 4.如果线程因为java.nio.channels.Selector被阻塞,则调用interrupt()方法会设置线程的中断状态,并且是selection操作返回一个非零的值,就好像调用了java.nio.channels.Selector的wakeup()方法一样。
     * 5.如果不是上述情况的任何一种,中断状态会被设置。
     * <p> Unless the current thread is interrupting itself, which is
     * always permitted, the {@link #checkAccess() checkAccess} method
     * of this thread is invoked, which may cause a {@link
     * SecurityException} to be thrown.
     *
     * <p> If this thread is blocked in an invocation of the {@link
     * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
     * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
     * class, or of the {@link #join()}, {@link #join(long)}, {@link
     * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
     * methods of this class, then its interrupt status will be cleared and it
     * will receive an {@link InterruptedException}.
     *
     * <p> If this thread is blocked in an I/O operation upon an {@link
     * java.nio.channels.InterruptibleChannel InterruptibleChannel}
     * then the channel will be closed, the thread's interrupt
     * status will be set, and the thread will receive a {@link
     * java.nio.channels.ClosedByInterruptException}.
     *
     * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
     * then the thread's interrupt status will be set and it will return
     * immediately from the selection operation, possibly with a non-zero
     * value, just as if the selector's {@link
     * java.nio.channels.Selector#wakeup wakeup} method were invoked.
     *
     * <p> If none of the previous conditions hold then this thread's interrupt
     * status will be set. </p>
     *
     * <p> Interrupting a thread that is not alive need not have any effect.
     *
     * @throws  SecurityException
     *          if the current thread cannot modify this thread
     *
     * @revised 6.0
     * @spec JSR-51
     */
    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();
    }

    /**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     * 检查当前线程是否被中断,并且中断状态将在调用这个方法的时候被清除。
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    /**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     * 验证线程是否被中断,中断状态不被清除。
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if this thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);

利用interrupt()方法、在run方法中判断线程是否被终止、以及合适的异常处理会很容易的停止一个线程。在Java中没有一种安全的抢占式方法来停止一个线程,因此也就没有安全的抢占式方法来停止任务。只有一些协作式机制,使得请求取消的任务和代码都遵循一种协商好的协议。

yeild()

/**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     *对线程调度器的一个提示,当前线程希望让出处理器。线程调度器可以忽略这个消息。
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     * yield是一种试图提高线程间相互进度的方法,否则会出现CPU的过度使用(???)
     * yield需要和详细的性能测试和基准测试结合起来,以保证可以实现想要的效果
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     * 很少有使用这个方法的情况。只有在测试的情况下。这个方法因为可能会提高竞态条件而重现bug.当设计并发控制构造器的时候,也可以使用yield。
     */
    public static native void yield();

并发代码中的大多数错误都是一些低概率的时间,因此在测试并发错误的时候需要反复地执行许多次,但有些方法可以提高这些错误的概率。在前面提到过,在多处理器系统上,如果处理器的数量少于活动线程的数量,那么与单处理器系统或者包含多个树立起的系统相比,将会产生更多的交替行为(上下文切换)。同样,如果在不同的处理器数量、操作系统以及处理器架构的系统上进行测试,就可以发现那些在特定运行环境下中才会出现的问题
有一种有用的方法可以提高交替操作的数量,以便能更有效的搜索程序的状态空间:在访问共享状态的操作中,使用Thread.yield将产生更多的上下文切换(这项技术的有效性与具体的平台相关,因为JVM可以将Thread.yield作为一个空操作。如果使用一个睡眠时间较短的sleep,那么虽然更慢些,但却更可靠。)
引用自《Java并发编程实战》

join()

/**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     * 等待这个线程结束。在millis毫秒内,线程结束,则当前线程继续向下运行。如果在millis毫秒以内,线程没有结束,则当前线程在millis时继续执行。
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     * join方法循环的调用isAlive和wait方法来实现当前线程持有this线程的锁,然后等待this线程。如果this线程执行完毕,则调用notifyAll()来通知当前线程。
     * 其实一个应用最好不要调用thread实例上的wait,notify,notifyAll方法。
     * 如果任何线程终端了当前线程,终端状态将会被清除,并且抛出异常InterruptedException。
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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;
            }
        }
    }

    /**
     * Waits at most {@code millis} milliseconds plus
     * {@code nanos} nanoseconds for this thread to die.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @param  nanos
     *         {@code 0-999999} additional nanoseconds to wait
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative, or the value
     *          of {@code nanos} is not in the range {@code 0-999999}
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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);
    }

因为wait会释放锁,所以join方法也会释放锁。

join方法有几个有趣的例子。请参考《Java多线程核心技术》

set(Default)UncaughtExceptionHandler()

set(Default)UncaughtExceptionHandler()方法关于线程的异常处理。之后介绍。

线程的状态

在start()方法中,需要通过判断线程的状态来确定是否是重新启动线程
许多抛出interruptedException的方法,几乎都与阻塞或者等待有关。
sleep(long)方法将RUNNABLE状态转换为TIMED_WAITING状态

线程有几种状态?

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.
         * 在JVM中运行,但是有可能正在等待处理器
         */
        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}.
         * 阻塞状态。
         * 一个线程在等待一个锁(原因是因为想要进入一个同步方法或同步代码块,或者在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.
         * 等待状态:
         * 一个线程处于等待状态有几种原因:
         * 1.object.wait()
         * 2.thread.join()
         * 3.lockSupport.park()
         * 处于等待状态的线程需要其他线程执行特定的操作才能转换成RUNNABLE状态。
         * wait()方法需要等待notify()或者notifyAll
         * join()方法需要等待另一个线程执行完毕
         * park()需要等待lockSupport.unpark()
         */
        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>
         * 限时等待状态
         * 1.sleep()
         * 2.wait(long)
         * 3.join(long)
         * 4.lockSupport.parkNanos()
         * 5.lockSupport.parkUntil()
         */
        TIMED_WAITING,

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

线程状态图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值