一、Thread 的方法简介
1、start
start 方法会开启一个新的线程,新线程会执行 run 方法,而调用完 start 方法后,程序在当前线程下接着执行 start 方法后面的程序。
特别注意 start 方法只能执行一次,如果执行多次方法(即使线程已经结束了)会报异常。
start 方法会将新线程加入到线程组,然后调用一个本地方法 start0
2、run
run 方法在线程调用 start 方法后会被线程自动执行。
如果直接调用 run 方法,将不会启动一个新线程,而只是执行一个函数。
start 和 run 区别示例
public class StartRunDemo {
static class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "调用了run");
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
//通过调用start启动一个新线程,自动执行run
myThread.start();
//在当前线程执行run
myThread.run();
}
}
3、yield(static)
yield 方法是让当前正在cpu上执行的线程让出cpu,让其他具有相同优先级的线程能够竞争获取cpu,但是当前线程也会加入cpu的竞争。
该方法很少使用,只有结合详细的分析和基准测试,才能让它发挥作用。常用语调试和测试,用于发现并发结构存在的问题。
特别注意:yield 不需要线程具有对象锁,也不会释放对象锁。
使用示例
public class YieldDemo {
private static Object monitor = new Object();
static class MyThread extends Thread{
@Override
public void run() {
// synchronized (monitor){//加入此条件,无法实现让出
for (int i = 0; i < 20; i++) {
if(i % 5 == 0){
System.out.println(this.getName() + " 让出cpu");
Thread.yield();
}
System.out.println(this.getName() + " i=" + i);
}
// }
}
}
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}
4、sleep(static)
sleep 方法让当前线程进入等待状态,线程会休眠指定时间,然后又变为 Runnable 状态。
特别注意:sleep 不需要线程具有对象锁,也不会释放对象锁。
使用示例
public class SleepDemo {
private static Object monitor = new Object();
static class MyThread extends Thread{
@Override
public void run() {
// synchronized (monitor){//加入此条件,在休眠期间不会释放锁
for (int i = 0; i < 20; i++) {
try {
System.out.println(this.getName() + "进入休眠");
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName() + " i=" + i);
}
// }
}
}
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}
5、join
让当前线程(调用 join 的线程)等待 join 方法所属的线程执行完毕。
特别注意:推荐不要调用 join 方法所属的线程的 wait、notify、notifyAll。因为 join 是通过 join 方法所属的线程的 wait 方法实现当前线程等待的。
使用示例
public class JoinDemo {
static class MyThread extends Thread{
@Override
public void run() {
System.out.println("JoinDemo is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("JoinDemo is runned");
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
myThread.join();//main线程将会阻塞此处,等待myThread执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("myThread 执行完毕,main开始执行");
}
}
6、interrupt
中断线程的具体行为:
- 当被中断的线程因为 wait、join、sleep 而阻塞,中断操作会清除中断状态,并且被中断的线程收到InterruptedException
- 被中断的线程因为I/O操作(基于java.nio.channels.InterruptibleChannel)而阻塞,中断操作会设置中断状态,并且被中断的线程会抛出异常ClosedByInterruptException
- 被中断的线程阻塞在selector时,中断操作会设置中断状态
- 如果不是以上情况,中断操作会设置中断状态。
中断一个处于 TEMINATED 的线程,没有任何操作。
终止处于阻塞状态的线程
@Override
public void run() {
try {
//执行任务
//因为某些原因将线程阻塞
} catch (InterruptedException ie) {
//因为interrupt中断阻塞状态的线程,会抛出InterruptedException
}
}
终止处于运行中的线程
interrupt 正在执行的线程,只会设置中断状态,所以需要根据中断状态终止线程。或者通过设置额外的中断标记,根据标记终止线程。
//方式一
@Override
public void run() {
while (!isInterrupted()) {
// 执行任务
}
}
//方式二
private volatile boolean flag = true;
protected void stopTask() {
flag = false;
}
@Override
public void run() {
while (flag) {
// 执行任务
}
}
终止线程的综合方式
@Override
public void run() {
try {
while (!isInterrupted()) {//根据中断标记,结束循环
// 执行任务
}
} catch (InterruptedException ie) {
//根据中断异常,结束循环
}
}
7、stop
已经被废弃了。参见《stop不安全》
8、suspend
已经被废弃了。参见《suspend、resume不安全》
9、resume
已经被废弃了。参见《suspend、resume不安全》
10、interrupted(static)、isInterrupted
interrupted 返回中断标记,并且清除中断标记
isInterrupted 返回中断标记,不清除中断标记
源码
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
二、Thread 的方法源码
public class Thread implements Runnable {
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
/* What will be run. */
private Runnable target;
/**
* 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.
*
* @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".
*/
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();
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static native Thread currentThread();
/**
* 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();
/**
* 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;
/**
* 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;
}
}
}
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @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 void join() throws InterruptedException {
join(0);
}
/**
* 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() {
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 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);
/**
* 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);
}
/**
* 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>
* 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.
* <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>.
*
* @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>.
*/
@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();
}
/**
* 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.
*
* @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>.
*/
@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();
}
/**
* Throws {@link NoSuchMethodError}.
*
* @deprecated This method was originally designed to destroy this
* thread without any cleanup. Any monitors it held would have
* remained locked. However, the method was never implemented.
* If if were to be implemented, it would be deadlock-prone in
* much the manner of {@link #suspend}. If the target thread held
* a lock protecting a critical system resource when it was
* destroyed, no thread could ever access this resource again.
* If another thread ever attempted to lock this resource, deadlock
* would result. 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>.
* @throws NoSuchMethodError always
*/
@Deprecated
public void destroy() {
throw new NoSuchMethodError();
}
/**
* 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();
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static native Thread currentThread();
private native void stop0(Object o);
private native void suspend0();
private native void resume0();
private native void interrupt0();
}