线程的状态和常用操作

一、线程的状态

  每个 Java 程序都有一个缺省的主线程,对于 Java 应用程序,主线程是 main()方法执行的线索;对于 Applet 程序,主线程是指挥浏览器加载并执行 Java Applet 程序的线索。要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即创建、就绪、运行、阻塞、终止。

 

 

 

1、新生状态

       在程序中用构造方法(new操作符)创建一个新线程时,如new Thread(r),该线程就是创建状态,此时它已经有了相应的内存空间和其它资源,但是还没有开始执行

2、就绪状态

       新建线程对象后,调用该线程的 start()方法就可以启动线程。当线程启动时,线程进入就绪状态(runnable)。由于还没有分配CPU,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。当系统挑选一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态。系统挑选的动作称之为“CPU调度"。一旦获得CPU线程就进入运行状态并自动调用自己的run方法。

3、运行状态

       当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run()方法。 run()方法定义了该线程的操作和功能。运行状态中的线程执行自己的run方法中代码。直到调用其他方法或者发生阻塞而终止。

4、阻塞状态

       一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入输出操作时,将让出 CPU 并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用 sleep()、 suspend()、 wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程转入就绪状态。重新到就绪队列中排队等待,这时被CPU调度选中后会从原来停止的位置开始继续执行。

      备注:阻塞被消除后是回到就绪状态,不是运行状态。

5、死亡状态

      线程调用 stop()方法、destory()方法或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。

      不推荐使用stop()方法【会产生异常】  destory()方法【destory是强制终止,不会释放锁】

 推荐使用boolen标识来停止线程,如下方式:

class TestThraed implements Runnable{
    private boolean flag = true;//线程使用标识
    @Override
    public void run() {
        while (flag) {
            for (int i = 0; i < 10; i++) {
                System.out.println("TestThread在运行"+i);
            }
        }
    }
    //停止线程
    public void stop(){
        //如果是extends Thread方式实现多线程。不能使用stop方法名。因为Thread类中对stop修饰为final不可重写
        this.flag = false;
    }
}

 

 

可以通过getState()方法来获取线程当前的状态:NEW 、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

线程的状态经典图:

 

分析上图:

1、线路1:新生-->就绪(Runnable)-->运行(Running)-->sleep或者join造成阻塞-->回到就绪(Runnable)-->运行(Running)-->死亡

2、线路2:新生-->就绪(Runnable)-->运行(Running)-->遇到synchronized,需要等待锁的释放。释放完成后-->回到就绪(Runnable)-->运行(Running)-->死亡

3、线路3:新生-->就绪(Runnable)-->运行(Running)-->遇到wait造成的等待需要唤醒notify。醒了后-->回到就绪(Runnable)-->运行(Running)-->死亡

 

 

二、线程的一些常用操作

方法名称 方法说明
public static int activeCount() 返回线程组中目前活动的现成的数目
pulic static native Thread  currentThread() 返回目前正在执行的线程  
public void destory() 销毁线程
public static int enumerate(Thread tarray[]) 将当前和子线程组中的活动线程拷贝至指定的线程数组
public final String getName() 返回线程的名称
public final int getPriority() 返回线程的优先级
public final ThreadGroup getThreadGroup() 返回线程的线程组
public static boolean interrupted() 判断目前线程是否被中断,如果是,返回true,否则返回false
public final native boolean isAlive() 判断线程是否在活动,如果是,返回true,否则返回false
public boolean interrupted() 判断目前线程是否被中断,如果是,返回true,否则返回false

public final void join() throws

InterruptedException

等待线程死亡

public final synchronized void join(long millis) throws

InterruptedException

等待millis毫秒后,线程死亡

public final synchronized void join(long millis, int nanos) throws

InterruptedException

 等待millis毫秒加上nanos微秒后,线程死亡
public void run()  执行线程
public final void   setName() 设定线程名称 
public final void   setPriority(int newPriority) 设定线程优先值 

public final native void sleep(long millis)

throws InterruptedException

使目前正在执行的线程休眠millis毫秒 

public static void sleep(long  millis, int nanos)

throws InterruptedException

使目前正在执行的线程休眠millis毫秒加上nanos微秒 
public native synchronized void start() 开始执行线程 
public String toString() 返回代表线程的字符串 
public static native void yield() 将目前正在执行的线程暂停, 允许其他线程执行 
//取得线程的名字
Thread t = Thread.currentThread();
String name = t.getName();
//设置线程的名字
SetNameThreadDemo tt = new SetNameThreadDemo();//继承Thread或者实现Runnable接口的线程类
tt.setName("test thread");
//判断线程是否启动
调用start()方法之前t.isAlive() = false
t.start();
调用start()方法之后t.isAlive() = true

线程的合并是指将某一个线程A在调用A.join()方法合并到正在运行的另一个线程B中,此时线程B处于阻塞状态需要等到线程A执行完毕后才开始线程B的继续执行,代码如下:线程的合并:join

public class JoinDemo {
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        Thread t1 = new Thread(t);
        t1.start();
        for (int i = 0; i < 100; i++) {
            /**
             * 当main线程中的i等于50的时候,就把t1线程合并到main线程中执行。此时main线程是处于阻塞状态
             * 直到t1线程执行完成后,main才开始继续执行
             */
            if (50==i) {
                t1.join();
            }
            System.out.println("main.."+i);
        }  
    }
}
class TestThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("join.."+i);
        }  
    }
}

join的执行结果如下:

main..0
.....省略.......
main..17
join..0
join..1
.....省略.......
main..49   //当main的i=50的时候就把t1合并到main线程中,直到t1线程执行完成后,才开始执行main线程。
join..5 - join..99
main..50
main..51 - main..99

线程的暂停:yield

该暂停方法暂停的时候不一定就暂停了,取决于CPU,假如刚暂停CPU调度又调到了该线程那就又启动了.....

public class YieldDemo {
    public static void main(String[] args) throws InterruptedException {
        TestThread1 t = new TestThread1();
        Thread t1 = new Thread(t);
        t1.start();
        for (int i = 0; i < 100; i++) {
            //当main线程中的i是20的倍数时,就暂停main线程
            if (i%20==0) {
                Thread.yield();//yield写在哪个线程体中,就暂停哪个线程。这里是在main里,就暂停main线程
                System.out.println("main线程暂停");
            }
            System.out.println("main.."+i);
        }  
    }
}
class TestThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("join.."+i);
        }  
    }
}

jield的执行结果如下:

main线程暂停
main..0
main..19
main线程暂停
main..20
main..39
main线程暂停
main..40
main..59
main线程暂停
main..79
main线程暂停
main..80
main..84
join..0
join..1

线程的(睡眠)暂停:sleep  休眠不释放锁【抱着锁睡觉

实例:10秒倒计时,当前线程每睡1秒就打印一个数字

public static void main(String[] args) throws InterruptedException {
    int num = 10;
    while (true) {
        System.out.println(num--);
        Thread.sleep(1000);
        if (num<=0) {
            break;             
        }
    }
}

守护线程(线程的后台运行)thread.setDaemon(true);

线程的后台运行

 1、对 Java 程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程在运行,这个进程就会结束。

 2、如果某个线程对象在启动(调用 start()方法)之前调用了 setDaemon(true)方法,这个线程就变成了后台线程。

public class ThreadDaemon {
    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        Thread thread = new Thread(t);
        thread.setDaemon(true);//设置后台运行
        thread.start();
    }
}
class ThreadTest implements Runnable{
    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName()+" is running");
        }
    }
}

三、总结

1、造成线程阻塞的方法?

阻塞线程的方法:join、yield、sleep 和Object的wait()方法

2、Java的守护进程(后台进程)?

设置线程为后台进程运行:setDaemon(true) 如果一个进程中只有后台线程在运行,这个进程就会结束。

3、造成线程阻塞后,线程回到哪个状态了?

通过join、yield、sleep造成线程阻塞后是回到了就绪状态

3、哪些状态之后是回到就绪状态?

 a)通过join、yield、sleep造成线程阻塞后是回到了就绪状态

 b)遇到synchronized后

 c)遇到Object的等待wait方法后

4、sleep会释放锁吗?

 sleep不会释放锁【它会抱着锁睡觉】

5、线程都有哪些状态?具体是怎么运行的?

线程有:创建、就绪、运行、阻塞、终止。5种状态

1.通过new关键字创建后,进入到新生状态

2.调用start后进入就绪状态

3.CPU调度到本线程后,本线程开始执行。进入到运行状态

4.运行中遇到join,yield,sleep造成阻塞,进入阻塞状态。阻塞完成后,又回到就绪状态

5.线程正常执行完,或者遇到异常终止后,进入死亡状态

6、终止线程有哪几种方法?

 线程调用 stop()方法、destory()方法或 run()方法执行结束后,线程即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。

 推荐使用boolen标识来停止线程

 

 

 

 

 

 

posted @ 2021-01-29 15:15  OFSqueque  阅读(357)  评论(0编辑  收藏  举报