Java线程状态的转换和API

Java线程状态的转换和API

线程状态

最权威的资料参考官方 Thread源码里的内部枚举 java.lang.Thread$State 的说明。其描述仅仅缺失了对于runnable状态更加细致的描述,runnable应该拆分成ready和running。

除了官方的资料,下面也会综合若干博客的资料图。有些状态的名称可能比较混乱,有多种叫法,甚至出现含义的差异,需要读者自行理解。

线程状态转换

image

注意:官方的runnable状态,细划分为就绪(ready)和运行中(running)。有些资料也把就绪叫做可运行,即直接把runnable当成就绪,官方的runnable其实是ready和running的统称

  • 线程被实例化后进入new
  • new状态的线程start()后进入ready,即可以被CPU挑选的状态
  • ready状态的线程被CPU挑选中,进入running
  • running若遇到synchronized,进入blocked
  • running若wait(),则放弃锁,进入waiting
  • running若sleep(timeout),进入timed_waiting(带有超时的等待状态)
  • running若yield()则让出时间片 或 时间片用完,进入ready(yield可能刚让出立即又被挑选
  • running若运行完毕,进入terminated
  • blocked的线程,在拿到锁后,进入ready(并非拿到锁立即可以运行
  • waiting和timed_waiting的线程,在其他线程通知后进入ready(并非被通知后立即可运行

补充说明

上述的版本是简单的版本

  • yield()让出时间片,只会让给相同优先级的其他线程
  • sleep(timeout)后,其他任意优先级的线程都有可能获得机会
  • 为什么wait()/notify()/notifyAll()方法是Object的而不是线程的,因为锁对象可以是任意的Object(包括java.lang.Thread对象),只要线程之间竞争的是同一个Object,即同一个锁,那么使用这个锁锁起来的代码,就能保证同一时间只有一个获锁线程能进入同步块。另外不同线程之间,就是使用同一个锁对象的wait()/notify()/notifyAll()进行通信的,线程之间的通信,总要有个共同的东西,这个共同的东西就是这个锁。

补充图1:
iamge

补充图2:
iamge

线程API

概述

(无)

API

有些是Object的接口,有些是Thread的,有些是LockSupport的

1、wait(timeout)/wait()

public final native void wait(long timeout) throws InterruptedException

public final void wait() throws InterruptedException,转调有参版

Object的方法,这个Object是所谓的锁对象,其实真正的锁对象应该是Object’s monitor才对吧? 所以这里的监视器的描述就是一般指的 “锁” 或 “锁对象”

  • 调用wait()等价于wait(0),后者是native方法

  • 调用wait(timeout)表示当前线程进入等待,并释放所持有的监视器,直到以下四种情况之一发生:

    • 别的线程通知notify,并被随机挑选为唯一被唤醒的线程
    • 别的线程通知notifyAll
    • 别的线程interrupt该线程
    • 如果timeout>0,指定的时间到了则被唤醒;如果timeout=0则此条规则无效

    该线程被唤醒后,跟其他线程无差别公平地竞争锁,等到获取了锁再从断点继续运行

  • 当前线程必须拥有锁(即该Object的监视器),即必须在synchronized方法或代码块里才能用wait方法

  • 要注意使用while来进行条件判断,而不是if,因为线程可能会打断(interrupts)和假醒(spurious)

synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }
/**
 * Causes the current thread to wait until either another thread invokes the
 * {@link java.lang.Object#notify()} method or the
 * {@link java.lang.Object#notifyAll()} method for this object, or a
 * specified amount of time has elapsed.
 * <p>
 * The current thread must own this object's monitor.
 * <p>
 * This method causes the current thread (call it <var>T</var>) to
 * place itself in the wait set for this object and then to relinquish
 * any and all synchronization claims on this object. Thread <var>T</var>
 * becomes disabled for thread scheduling purposes and lies dormant
 * until one of four things happens:
 * <ul>
 * <li>Some other thread invokes the {@code notify} method for this
 * object and thread <var>T</var> happens to be arbitrarily chosen as
 * the thread to be awakened.
 * <li>Some other thread invokes the {@code notifyAll} method for this
 * object.
 * <li>Some other thread {@linkplain Thread#interrupt() interrupts}
 * thread <var>T</var>.
 * <li>The specified amount of real time has elapsed, more or less.  If
 * {@code timeout} is zero, however, then real time is not taken into
 * consideration and the thread simply waits until notified.
 * </ul>
 * The thread <var>T</var> is then removed from the wait set for this
 * object and re-enabled for thread scheduling. It then competes in the
 * usual manner with other threads for the right to synchronize on the
 * object; once it has gained control of the object, all its
 * synchronization claims on the object are restored to the status quo
 * ante - that is, to the situation as of the time that the {@code wait}
 * method was invoked. Thread <var>T</var> then returns from the
 * invocation of the {@code wait} method. Thus, on return from the
 * {@code wait} method, the synchronization state of the object and of
 * thread {@code T} is exactly as it was when the {@code wait} method
 * was invoked.
 * <p>
 * A thread can also wake up without being notified, interrupted, or
 * timing out, a so-called <i>spurious wakeup</i>.  While this will rarely
 * occur in practice, applications must guard against it by testing for
 * the condition that should have caused the thread to be awakened, and
 * continuing to wait if the condition is not satisfied.  In other words,
 * waits should always occur in loops, like this one:
 * <pre>
 *     synchronized (obj) {
 *         while (&lt;condition does not hold&gt;)
 *             obj.wait(timeout);
 *         ... // Perform action appropriate to condition
 *     }
 * </pre>
 * (For more information on this topic, see Section 3.2.3 in Doug Lea's
 * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
 * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
 * Language Guide" (Addison-Wesley, 2001).
 *
 * <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
 * interrupted} by any thread before or while it is waiting, then an
 * {@code InterruptedException} is thrown.  This exception is not
 * thrown until the lock status of this object has been restored as
 * described above.
 *
 * <p>
 * Note that the {@code wait} method, as it places the current thread
 * into the wait set for this object, unlocks only this object; any
 * other objects on which the current thread may be synchronized remain
 * locked while the thread waits.
 * <p>
 * This method should only be called by a thread that is the owner
 * of this object's monitor. See the {@code notify} method for a
 * description of the ways in which a thread can become the owner of
 * a monitor.
 *
 * @param      timeout   the maximum time to wait in milliseconds.
 * @throws  IllegalArgumentException      if the value of timeout is
 *               negative.
 * @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of the object's monitor.
 * @throws  InterruptedException if any thread interrupted the
 *             current thread before or while the current thread
 *             was waiting for a notification.  The <i>interrupted
 *             status</i> of the current thread is cleared when
 *             this exception is thrown.
 * @see        java.lang.Object#notify()
 * @see        java.lang.Object#notifyAll()
 */
public final native void wait(long timeout) throws InterruptedException;

2、notify()

public final native void notify()

  • 通知该Object上等待的线程,如果有多个,随意一个会被通知
  • 当前线程必须有该Object的锁,即notify必须写在synchronized的方法或代码块里
  • 调用notify后,当前线程并不是立即释放锁的,要等到同步方法或同步代码块执行完
  • 被通知的线程必须等到锁后才能恢复运行,恢复到调用wait()的时刻
  • 被通知的线程会参与到锁的竞争中,没有优势也没有劣势,公平竞争
/**
 * Wakes up a single thread that is waiting on this object's
 * monitor. If any threads are waiting on this object, one of them
 * is chosen to be awakened. The choice is arbitrary and occurs at
 * the discretion of the implementation. A thread waits on an object's
 * monitor by calling one of the {@code wait} methods.
 * <p>
 * The awakened thread will not be able to proceed until the current
 * thread relinquishes the lock on this object. The awakened thread will
 * compete in the usual manner with any other threads that might be
 * actively competing to synchronize on this object; for example, the
 * awakened thread enjoys no reliable privilege or disadvantage in being
 * the next thread to lock this object.
 * <p>
 * This method should only be called by a thread that is the owner
 * of this object's monitor. A thread becomes the owner of the
 * object's monitor in one of three ways:
 * <ul>
 * <li>By executing a synchronized instance method of that object.
 * <li>By executing the body of a {@code synchronized} statement
 *     that synchronizes on the object.
 * <li>For objects of type {@code Class,} by executing a
 *     synchronized static method of that class.
 * </ul>
 * <p>
 * Only one thread at a time can own an object's monitor.
 *
 * @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of this object's monitor.
 * @see        java.lang.Object#notifyAll()
 * @see        java.lang.Object#wait()
 */
public final native void notify();

3、notifyAll()

public final native void notifyAll()

  • 跟notify完全一样,唯一的不同是它会通知所有Object上等待的线程

4、join(timeout)/join()

public final synchronized void join(long millis) throws InterruptedException

public final void join() throws InterruptedException,转调有参版

  • 当前线程等待目标线程一定时间,或等到目标线程运行结束(die)再继续执行,两个条件以先达到的为准

    例如代码 t.join(),意思是当前线程,就是执行t.join()代码的那个线程(假设是M)必须等到t线程执行完毕,t.join()后面的代码才能继续被M执行。

    join的意思就是将t join到 M 里,只要t没完成,M就卡在t.join()这里,这就是join的含义。

  • 上述说的join(),等价于join(0)

  • join()通常用在main线程里,所有其他线程执行完毕再结束main线程

  • 实现:其内部使用wait来实现,非native方法。

    相当简单,主线程是M,执行t.join(0),join方法是同步的,M获得锁(t是锁对象),isAlive()判断的是t是否还活着,如果还未结束,执行wait(0),于是M就释放锁,进入到wait队列。等t运行结束的时候执行t的notifyAll(在native代码里,参考这里),这样M线程恢复了执行。这样就实现了M等t执行完再执行

思考:

其实join(timeout)真的很像sleep(timeout),不同点是join(timeout)无需一定等到timeout,在目标线程结束后即可终止等待。而join()的话可以实现无限等,而sleep是没对应的。另外从机制上两者是不同的

写例子帮助理解join

要实现其他线程都执行完,main线程才最后执行(做收尾工作),有三种方式

  • 使用join()
  • 使用CountDownLatch
  • 使用yield()

使用join()

// 结论:main线程不等待t线程完成,自己先打印了结果
// 将代码 t.join()打开后,当前线程(main线程)
// 会等待目标线程(t,就是join()的方法那个)执行完毕才继续
// 所谓 "执行完毕",就是 t 线程的run方法执行完线程死掉了
public static void main(String[] args) throws Exception {

	Thread t = new Thread(new Runnable() {

		@Override
		public void run() {
			for (int i = 0; i < 5; i++) {
				System.out.println("threadName:" + Thread.currentThread().getName() + ",i= " + i);

				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	});
	t.start();
    // t.join();
	System.out.println("threadName:" + Thread.currentThread().getName());
}

使用yield()

// 也可以把上述代码 t.join() 换成如下也能达到效果
// main线程加上t线程一共是2个活动线程,所谓active意思就是还没死
// 如果t运行完了死了,activeCount就会变成1,那么就会跳出循环了
// 注意:前面学习yield()的时候,API文档说了yield()是个信号,调度器
// 可以忽略。但是没关系,因为是个while循环,忽略的是依然还在循环内
while(Thread.activeCount() > 1) {
	Thread.yield();
}

使用CountDownLatch

// PS:CountDownLatch 允许多线程操作
public class JoinTest {
	private static CountDownLatch countDownLatch = new CountDownLatch(1);
	
	public static void main(String[] args) throws Exception {

		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				for (int i = 0; i < 5; i++) {
					System.out.println("threadName:" + Thread.currentThread().getName() + ",i= " + i);

					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				// 线程run方法结尾
				countDownLatch.countDown();
			}
		});
		t.start();
		
		countDownLatch.await();
		
		
		System.out.println("threadName:" + Thread.currentThread().getName());
	}
}

join(timeout)的源码

/**
 * Waits at most {@code millis} milliseconds for this thread to
 * die. A timeout of {@code 0} means to wait forever.
 *
 * <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
 *
 * @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;
        }
    }
}

5、sleep(timeout)

  • 当前线程进入睡眠(暂停执行),如果持有锁,不放弃
  • sleep()可以使低优先级的线程得到执行的机会,也可以让同优先级、高优先级的线程有执行的机会
  • 当线程sleep时被interrupt,会立刻抛出InterruptedException异常并不会一直等到睡眠时间过去
# 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:
* subject to:应该是 "取决于""受制于"
* precision 和 accuracy 都有精度的意思,后者好像是偏向 "准确度"
总的意思是:睡眠多长时间的事情决定于系统的计时器和调度器的精度和准确性

/**
 * 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.
 */
public static native void sleep(long millis) throws InterruptedException;

6、yield()

  • 可能用于debug比较多的方法
  • 放弃当前CPU片不会释放锁
  • 先检测当前是否有相同优先级的线程处于可运行状态,如有,则把CPU的占有权交给该线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它只把运行机会让给了同等级的其他线程
# It is rarely appropriate to use this method:意思应该是很有有使用这个方法(的场景),就是"这方法很少用"

# The scheduler is free to ignore this hint:
调度器可以忽略(让出CPU时间片的)提示,be free to,自由去做,即可做可以不做

# Yield is a heuristic attempt to improve relative progression
between threads that would otherwise over-utilise a CPU
* heuristic attempt:启发式的尝试,因为前面有句话 "调度器可能会忽略yield",所以这个是个启发式的,并不是强制的
* relative progression:相对发展,就是说不要A线程执行很多,B线程很少,大家平均发展,大概是这意思

yield是提醒式的尝试,该尝试能改进进程间的相对发展(均匀点发展),否则这些进程会过度使用CPU。


 
 
/**
 * 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.
 *
 * <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.
 */
public static native void yield();

7、interrupt()

public void interrupt()

(略,待补充)

/**
 * Interrupts this thread.
 *
 * <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() {

8、interrupted() / isInterrupted()

public static boolean interrupted()

public boolean isInterrupted()

  • isInterrupted():成员方法,检查目标线程是否曾被中断(例如t.isInterrupted检查的是t),不清理中断标记
  • interrupted(),是静态方法,检查当前线程是否曾被中断,清理中断标记
  • 是否清理中断标记的影响是,中断标记表示是否中断过,清理后变成未中断,也就是清理标记后第二次调用接口得到的就是未中断过。不清理标记,接口就有幂等性,多次重复调用得到相同的结果
/**
 * 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);

9、isAlive

public final native boolean isAlive()

  • 判断本进程是否活着,线程还未结束(died)就是还活着,当然必须是started的
/**
 * Tests if this thread is alive. A thread is alive if it has
 * been started and has not yet died.
 *
 * @return  <code>true</code> if this thread is alive;
 *          <code>false</code> otherwise.
 */
public final native boolean isAlive();

10、activeCount()

public static int activeCount()

  • 获取当前线程所在组及其子组的活跃进程数(直接子组,间接子组,递归累加)
  • 该方法是个估计值,因为线程在动态变化中(这个肯定不可能停所有线程取快照计算的)
  • 该方法主要用于debug和监测
/**
 * Returns an estimate of the number of active threads in the current
 * thread's {@linkplain java.lang.ThreadGroup thread group} and its
 * subgroups. Recursively iterates over all subgroups in the current
 * thread's thread group.
 *
 * <p> The value returned is only an estimate because the number of
 * threads may change dynamically while this method traverses internal
 * data structures, and might be affected by the presence of certain
 * system threads. This method is intended primarily for debugging
 * and monitoring purposes.
 *
 * @return  an estimate of the number of active threads in the current
 *          thread's thread group and in any other thread group that
 *          has the current thread's thread group as an ancestor
 */
public static int activeCount() {
    return currentThread().getThreadGroup().activeCount();
}

11、LockSupport.park()

一系列方法

  • public static void park()
  • public static void park(Object blocker)
  • public static void parkNanos(long nanos),1秒=11000毫秒=110001000微秒=1100010001000纳秒
  • public static void parkUntil(long deadline),deadline是类似System.currentTimeMillis(),单位是毫秒跟parkNanos单位不一样
  • public static void parkNanos(Object blocker, long nanos)
  • public static void parkUntil(Object blocker, long deadline)

区别是:1、是否带时间(指定时长或指定时间点),2、blocker

  • 如果没有许可,该方法要阻塞(线程进入休眠),否则方法立即返回
  • parkNanos、parkUtil等带时间的版本,如果有许可也立即返回,如果没许可,则等到超时就返回
  • 进入休眠的线程,发生以下三种之一则退出休眠
    • 其他线程调用unpark,参数是当前线程,如unpark(当前线程)
    • 其他线程interrupt当前线程
    • 假醒
补充
  • 跟sleep的区别是

    • sleep一定要设置时间,park可选
    • sleep可以超时或被打断而被唤醒,park可以超时或通过其他线程的unpark来唤醒
  • 跟wait()的区别是

    • wait会放弃锁,进入等待,必须写在synchronized方法/块里,而park不需要
    • wait要别的线程notify,自己不行,但是unpark可以是自己先unpark,然后在自己park,当然自己如果先进入park肯定得别的线程进行unpark了
  • park和unpark

    • 先unpark一次,再park,则park不会阻塞
    • 也可以unpark多次,在park,则park不会阻塞
    • unpark一次,再park不会阻塞,再park就会阻塞,因为许可已经被消费了(这就是为什么API文档里用了consumed这个单词,是会被消耗掉的)
    • unpark两次,再park不会被阻塞,再park还是被阻塞,说明消费钱unpark多少次都是发放一次许可
    • unpark一次,再park不会被阻塞,再unpark,再park不会被阻塞。说明许可发放一次被消费后可以再发放
public static void main(String[] args) {
	// 打印出a、b
	LockSupport.unpark(Thread.currentThread());
	LockSupport.park();
	System.out.println("a");
	
	LockSupport.unpark(Thread.currentThread());
	LockSupport.park();
	System.out.println("b");
}
  • park中的线程可以被interrupt,但是不会抛出异常
// 打印
// t1,park
// t1,park end
public static void main(String[] args) {
	Thread t1 = new Thread(new Runnable() {

		@Override
		public void run() {
			System.out.println("t1,park");
			try {
				LockSupport.park();
			} catch (Exception e) {
				System.out.println("测试park被中断");
			}
			System.out.println("t1,park end");

		}
	});
	t1.start();

	try {
		Thread.sleep(2000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	
	t1.interrupt();
}

Disables the current thread for thread scheduling purposes unless the permit is available
除非有许可,为了线程调度目的,禁用当前线程。for ... purposes,为了...目的(短语,purposes就是用复数)

If the permit is available then it is consumed and the call returns immediately
意思是如果有许可,该方法不会阻塞,而是立即返回。选择性忽略一些语句,例如`then it is consumed`,这个意思比较细,"如果有许可,那么许可会被使用,调用该方法会立即返回",这里consumed应该是使用该许可的意思。


/**
 * Disables the current thread for thread scheduling purposes unless the
 * permit is available.
 *
 * <p>If the permit is available then it is consumed and the call
 * returns immediately; otherwise the current thread becomes disabled
 * for thread scheduling purposes and lies dormant until one of three
 * things happens:
 *
 * <ul>
 *
 * <li>Some other thread invokes {@link #unpark unpark} with the
 * current thread as the target; or
 *
 * <li>Some other thread {@linkplain Thread#interrupt interrupts}
 * the current thread; or
 *
 * <li>The call spuriously (that is, for no reason) returns.
 * </ul>
 *
 * <p>This method does <em>not</em> report which of these caused the
 * method to return. Callers should re-check the conditions which caused
 * the thread to park in the first place. Callers may also determine,
 * for example, the interrupt status of the thread upon return.
 */
public static void park() {
    UNSAFE.park(false, 0L);
}

12、LockSupport.unpark(thread)

public static void unpark(Thread thread)

  • 如果某个线程还没有许可,给它许可(也就是说有了就不会给,所以该方法可以重复调用)
  • 如果这个线程正被park阻塞,则调用unpark后它就不阻塞了
  • 如果这个线程还没被park阻塞,则它调用park的时候已经有许可了,所以届时不阻塞
  • 如果线程还未start,调用unpark(thread)不发生任何影响

Makes available the permit for the given thread, if it was not already available.
这句的主谓宾定状补语法比较难理解。

/**
 * Makes available the permit for the given thread, if it
 * was not already available.  If the thread was blocked on
 * {@code park} then it will unblock.  Otherwise, its next call
 * to {@code park} is guaranteed not to block. This operation
 * is not guaranteed to have any effect at all if the given
 * thread has not been started.
 *
 * @param thread the thread to unpark, or {@code null}, in which case
 *        this operation has no effect
 */
public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

猜你喜欢

转载自blog.csdn.net/w8y56f/article/details/89554175