多线程详解二


1.线程的状态

在Java1.4及以下的版本中,每个线程都具有新建、可运行、阻塞、死亡四种状态,但是在Java5.0及以上版本中, 线程的状态被扩充为新建、可运行、阻塞、等待、定时等待、死亡六种。线程的状态完全包含了一个线程从新建到运行, 最后到结束的整个生命周期。线程状态的具体信息如下:

①NEW(新建状态、初始化状态):线程对象已经被创建,但是还没有被启动时的状态。这段时间就是在我们调用new命令之后,调用start()方法之前。

②RUNNABLE(可运行状态、就绪状态):在我们调用了线程的start()方法之后线程所处的状态。处于RUNNABLE状态的线程在JAVA虚拟机(JVM)上是运行着的,但是它可能还正在等待操作系统分配给它相应的运行资源以得以运行。

③BLOCKED(阻塞状态、被中断运行):线程正在等待其它的线程释放同步锁,以进入一个同步块或者同步方法继续运行;或者它已经进入了某个同步块或同步方法,在运行的过程中它调用了某个对象继承自java.lang.Object的wait()方法,正在等待重新返回这个同步块或同步方法。

④WAITING(等待状态):当前线程调用了java.lang.Object.wait()、java.lang.Thread.join()或者java.util.concurrent.locks.LockSupport.park()三个中的任意一个方法,正在等待另外一个线程执行某个操作。比如一个线程调用了某个对象的wait()方法,正在等待其它线程调用这个对象的notify()或者notifyAll()(这两个方法同样是继承自Object类)方法来唤醒它;或者一个线程调用了另一个线程的join()(这个方法属于Thread类)方法,正在等待这个方法运行结束。

⑤TIMED_WAITING(定时等待状态):当前线程调用了 java.lang.Object.wait(long timeout)、 java.lang.Thread.join(longmillis)、 java.util.concurrent.locks.LockSupport.packNanos(long nanos)、 java.util.concurrent.locks.LockSupport.packUntil(long deadline) 四个方法中的任意一个,进入等待状态,但是与WAITING状态不同的是,它有一个最大等待时间,即使等待的条件仍然没有满足,只要到了这个时间它就会自动醒来。

⑥TERMINATED(死亡状态、终止状态):线程完成执行后的状态。线程执行完run()方法中的全部代码,从该方法中退出,进入TERMINATED状态。还有一种情况是run()在运行过程中抛出了一个异常,而这个异常没有被程序捕获,导致这个线程异常终止进入TERMINATED状态。


在Java5.0及以上版本中,线程的全部六种状态都以枚举类型的形式定义在java.lang.Thread类中了,代码如下:

public enum State {
	NEW,
	RUNNABLE,
	BLOCKED,
	WAITING,
	TIMED_WAITING,
	TERMINATED;
}

2.sleep()和wait()的区别

sleep()方法和wait()方法都成产生让当前运行的线程停止运行的效果,这是它们的共同点。下面我们来详细说说它们的不同之处。

①sleep()方法是本地方法,属于Thread类,它有两种定义:

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



public static void sleep(long millis, int nanos) throws InterruptedException {
    //other code
}

其中的参数millis代表毫秒数(千分之一秒),nanos代表纳秒数(十亿分之一秒)。这两个方法都可以让调用它的线程沉睡(停止运行)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE),但这并不表示它马上就会被运行,因为线程调度机制恢复线程的运行也需要时间。调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。上面的两个方法都声明抛出一个InterruptedException类型的异常,这是因为线程在sleep()期间,有可能被持有它的引用的其它线程调用它的interrupt()方法而中断。中断一个线程会导致一个InterruptedException异常的产生,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

为了更好地理解interrupt()效果,我们来看一下下面这个例子:

public class InterruptTest {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                try {
                    System.out.println("我被执行了-在sleep()方法前");
                    // 停止运行10分钟
                    Thread.sleep(1000 * 60 * 10);
                    System.out.println("我被执行了-在sleep()方法后");   
                } catch (InterruptedException e) {   
                    System.out.println("我被执行了-在catch语句块中");   
                }   
                System.out.println("我被执行了-在try{}语句块后");   
            }
        };   
        // 启动线程 
        t.start();   
        // 在sleep()结束前中断它
        t.interrupt();   
    }   
}  

运行结果:

我被执行了-在sleep()方法前

我被执行了-在catch语句块中

我被执行了-在try{}语句块后


②wait()方法也是本地方法,属于Object类,有三个定义:

public final void wait() throws InterruptedException {
}


public final native void wait(long timeout) throws InterruptedException;


public final void wait(long timeout, int nanos) throws InterruptedException {
}

wait()和wait(long timeout,int nanos)方法都是基于wait(long timeout)方法实现的。同样地,timeout代表毫秒数,nanos代表纳秒数。当调用了某个对象的wait()方法时,当前运行的线程就会转入等待状态(WAITING),等待别的线程再次调用这个对象的notify()或者notifyAll()方法(这两个方法也是本地方法)唤醒它,或者到了指定的最大等待时间,线程自动醒来。如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法同样会被Thread类的interrupt()方法中断,并产生一个InterruptedException异常,效果同sleep()方法被中断一样。

在本章中主要简单介绍了线程的状态及sleep()和wait()方法,在下一章中将主要介绍实现同步的方式、synchronized关键字和Lock接口。




联系我们 | 友情链接