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高并发程序设计》 --葛一鸣 郭超