Thread.State的状态
jdk中关于线程状态的描述:
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;
}
- New:新创建的一个线程对象
- Runnable:就绪状态,线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于"可运行线程池"中,变得可运行,此时等待操作系统的其他资源,比如处理器。
- TimedWaiting:等待特定的时间,调用下面函数时,线程处于该状态
- Thread.sleep
- Object.wait with timeout (有参数的)
- Thread.join with timeout
- LockSupport.parkNanos
- LockSupport.parkUntil
-
WAITING:等待,调用下面参数时,该线程处于该状态
- Object.wait with no timeout
- Thread.join with no timeout
- LockSupport.park
- BLOCKED:阻塞状态,当其他线程调用Object.wait后,若该线程要进入同样的synchronized块,则该线程状态变为阻塞状态
-
TERMINATED:线程执行结束,变为该状态
package zt.thread; import java.util.ArrayList; import java.util.List; /** * <p>标题:模拟生产者消费者</p> * <p>描述:生产者少,消费者多,并且生产慢,那么就会产生阻塞</p> * <p>编译者:zt</p> */ public class Plate { private List<Object> eggs = new ArrayList<Object>(); public synchronized void getEgg() throws InterruptedException{ while(eggs.size() == 0) { wait(); } eggs.remove(0); System.out.println("消费一个鸡蛋,当前还剩: " + eggs.size()); notifyAll(); } public synchronized void putEgg() throws InterruptedException { while(eggs.size() == 1000000){ wait(); } eggs.add(new Object()); Thread.sleep(200); System.out.println("添加一个鸡蛋,当前还剩: " + eggs.size()); notifyAll(); } public static void main(String[] args) { Plate plant = new Plate(); //生产线程 for(int i = 0; i < 2; i++) { new Thread(new Runnable(){ public void run() { try { while(true){ plant.putEgg(); } } catch (InterruptedException e) { e.printStackTrace(); } } }, "putegg"+i).start(); } //消费线程 for(int i = 0; i < 3; i++) { new Thread(new Runnable(){ public void run() { try { while(true){ plant.getEgg(); } } catch (InterruptedException e) { e.printStackTrace(); } } }, "getegg"+i).start(); } } }
使用工具查看:
在dos命令中使用:
-
jps查看进程号:
-
使用jstack查看线程状态,可以看到,有的线程被阻塞,有的处于TIMEWAITING中
常用函数
- 中断:
- public void interrupt() // 中断线程
- public boolean isInterrupted() // 判断是否被中断
- public static boolean interrupted() // 判断是否被中断,并清除当前中断状态
调用Interrupted,不会中断一个正在运行的线程。线程会不时的检测中断标志位以判断线程是否应该被中断(中断标识值是否为true),中断只会影响到wait状态、sleep状态、join状态。被打断的线程会抛出InterruptedException。
如果在正常运行的程序中添加while(!Thread.interrupted()),则同样可以在中断后离开代码体。
jdk中关于这三者的描述:
中断线程,只是设置中断标志。
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();
}
判断是否被中断,并清除中断位:
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);
2. stop函数:这个方法并不安全,若当前的线程获得了monitor,正在执行,使用stop会直接释放monitor,那么就有可能导致数据不一致。
package zt.thread1;
/**
* <p>标题:测试stop函数</p>
* <p>描述:执行stop有时会导致数据不一致</p>
* <p>编译者:zt</p>
*/
public class ThreadStopTest {
public static void main(String[] args) {
Class1 class1 = new Class1();
Thread test = new Thread(new Runnable(){
public void run(){
class1.update();
}
});
test.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.stop();
System.out.println(class1.toString());
}
}
class Class1 {
int i = 0;
int j = 0;
public synchronized void update(){
i = 1;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
j = 1;
}
public String toString(){
return "i = " + i + "; j = " + j;
}
}
上面例子的执行结果是:
解决方式与中断的方式类似:可以设置一个标识,不断去查询这个标识值是否发生了改变。这个例子没有那么合适,因为在循环体中会不断的去执行更新操作。
package zt.thread1;
/**
* <p>标题:测试替代stop函数</p>
* <p>描述:执行stop有时会导致数据不一致</p>
* <p>编译者:zt</p>
*/
public class ThreadReplaceStopTest {
public static void main(String[] args) {
Class2 class2 = new Class2();
ReplaceStopThread test = new ReplaceStopThread(class2);
test.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.stop1();
System.out.println(class2.toString());
}
}
class ReplaceStopThread extends Thread {
private volatile Thread blinker;
Class2 class2;
public ReplaceStopThread(Class2 class2){
this.class2 = class2;
}
public void stop1() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
blinker = Thread.currentThread();
while (blinker == thisThread) {
class2.update();
Thread.yield();
}
}
}
class Class2 {
int i = 0;
int j = 0;
public synchronized void update(){
i = 1;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
j = 1;
System.out.println("changeall");
}
public String toString(){
return "i = " + i + "; j = " + j;
}
}
3. suspend(挂起) 与resume(继续执行) 函数
若线程没有suspend的情况下就执行resume方法会抛出异常。在调用suspend前就调用resume,那么线程就会一直挂起,如果还有锁那么就会死锁。suspend()不会释放锁
/**
* 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();
}
当调用suspend后,线程仍然处于RUNNABLE状态:
/**
* <p>标题:测试线程suspend函数</p>
* <p>描述:</p>
* <p>编译者:zt</p>
*/
public class ThreadSuspendTest {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable(){
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1");
t1.start();
t1.suspend();
}
}
使用jsack查看此时的t1线程状态,处于RUNNABLE:
4. join函数:本质是不断的调用wait(0),当线程执行完成后,系统内部会调用notifyAll()函数。jdk中的描述:
/**
* 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);
}
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. yield函数:一旦执行,会使当前线程让出CPU,当前线程让出CPU后,还会进行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();
多线程异常的捕获
package zt.thread1;
import java.lang.Thread.UncaughtExceptionHandler;
/**
* <p>标题:获得线程异常</p>
* <p>描述:</p>
* <p>编译者:zt</p>
*/
public class GetThreadException {
public static void main(String[] args) {
try{
new Thread(new Runnable(){
public void run() {
int i = 1/0;
}
}, "testThread1").start();
}catch(Exception e){
System.out.println("testThread1 捕获异常");
}
Thread testThread2 = new Thread(new Runnable(){
public void run() {
int i = 1/0;
}
});
testThread2.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("testThread2捕获异常");
}
});
testThread2.start();
}
}
此外,通过查看jdk源码发现,异常还与defaultUncaughtExceptionHandler、ThreadGroup有关。
参考
《实战Java高并发程序设计》 --葛一鸣 郭超