线程的几种状态

这个是面试经常被问到的问题,多线程的话首先要对线程的状态有个清晰的认识才可以;这里做个简单的总结;

1.新建状态(new):新创建一个线程对象的初始状态;也就是通过new关键字创建一个线程对象,;,但并没有调用start方法时候的状态;

Thread t = new thread ( tt)

2.就绪状态(Runnable):线程有资格运行,但调度程序还没有把它选为运行线程时的状态,此时,线程具备运行的条件,一旦被选中,马上就可以执行。线程创建后,调用了start方法,线程不处于运行状态;该状态下,等待操作系统的调度,获取cpu使用权之后就可以执行线程代码;

3.运行状态:从就绪状态池中被选择为当前执行的线程的状态;

4.阻塞状态(Blocked):线程在执行的过程中,遇到被synchronized关键字保护的代码,等待获得被保护对象的锁,此时线程会停止执行;这个地方要注意,只有synchronized锁才会让线程进入到Blocked状态,等待利用cas实现的锁(ReentrantLock),线程仍然处于Runnable状态。

5.等待状态(WATTING):线程处于等待状态只有一种情况,就是调用wait方法,如下所示

public static void timedWaiting() {
        final Object lock = new Object();
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
            }
        }
    }

6.死亡状态(Dead):线程执行完了或者异常退出run方法,线程结束生命周期;

---------------------------------------------------------------------------------------------------------------------

其他的一些说明:

1> wait和sleep方法的区别

wait方法和sleep方法都可以使线程处于等待状态,区别是,wait方法会释放对象的锁,而sleep方法则不会;

两个方法分别来自不同的类,wait是object对象的方法,而sleep是线程Thread类的方法;

wait,notify和notifyAll只能用在同步控制方法或者同步控制块中,而sleep方法可以在任何地方使用;

sleep方法属于thread类中的方法,表示让一个线程进入休眠状态,等待一定时间之后,自动醒来进入到可运行状态,只对当前线程有效,而wait属于Object方法,一旦一个对象调用了wait方法,必须采用notify和notifyAll方法唤醒该进程;

如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法,如果此刻线程B处于wait/sleep/join,则线程B会立刻抛出InterruptedException error;

wait()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronizedblock中进行调用,虽然能编译通过,但在运行时会发生illegalMonitorStateException的异常。

2>join方法

join方法用于在某一个线程执行的过程中调用另一个线程,等到被调用的线程执行结束后,再继续执行当前线程,理解就是讲线程从并行变成串行;举个简单的例子说明

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小东");
        t1.start();
        /**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
         程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
         所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
         */
        t1.join();
        t2.start();
    }

}
class ThreadJoinTest extends Thread{
    public ThreadJoinTest(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

上面程序结果是先打印完小明线程,在打印小东线程;join方法也可以传递一个参数

ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小东");
        t1.start();
        /**join方法可以传递参数,join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后,
         * main线程和t1线程之间执行顺序由串行执行变为普通的并行执行
         */
        t1.join(10);
        t2.start();

所以,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。

注意:join必须用在start方法后面,否则没有任何作用,因为线程还没有开始,调用join方法将毫无意义;

join方法的实现原理:其实还是调用线程的wait方法来达到同步的目的。例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

3>多线程wait和notify判断条件时,一定使用while,而不是if,举个例子:如果有两个生产者A和B,一个消费者C。当存储空间满了之后,生产者A和B都被wait,进入等待唤醒队列。当消费者C取走了一个数据后,如果调用了notifyAll(),注意,此处是调用notifyAll(),则生产者线程A和B都将被唤醒,如果此时A和B中的wait不在while循环中而是在if中,则A和B就不会再次判断是否符合执行条件,都将直接执行wait()之后的程序,那么如果A放入了一个数据至存储空间,则此时存储空间已经满了;但是B还是会继续往存储空间里放数据,错误便产生了;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值