线程生命周期和常用方法

1.线程生命周期

线程的生命周期有五个:

  • 新建状态
  • 就绪状态(可运行状态)
  • 运行状态
  • 阻塞状态
  • 死亡状态

图解:

2.线程常用方法

线程有哪些方法可以查看api文档中的Thread类,以下只列举常用的。

(1)线程名字相关方法

  • void setName(String name):设置线程的名字(不设置也有默认名);
  • String getName():获取线程的名字;

例:

package com.dh.thread;

public class Thread04 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyThread04());
        //默认名称
        System.out.println(t.getName());
        //设置线程名称
        t.setName("t");
        //再次获取名称
        System.out.println(t.getName());

        //再新建一个线程
        Thread t2 = new Thread(new MyThread04());
        System.out.println(t2.getName());
    }
}

class MyThread04 implements Runnable{

    @Override
    public void run() {
    }
}

结果:

Thread-0
t
Thread-1

如果不设置名字的话,线程的名字就为Thread-数字(从0开始)。

(2)获取当前线程对象

  • static Thread currentThread():返回当前线程对象。

例:

package com.dh.thread;

public class Thread05 {

    public static void main(String[] args) {
        //此时当前线程为main线程
        System.out.println(Thread.currentThread().getName());
        Thread t = new Thread(new MyThread05());
        t.setName("t");
        t.start();
        //t线程启动后,当前线程就是t线程
    }
}

class MyThread05 implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

结果:

main
t

该结果也可以看出,main()主线程的名字为main。

(3)线程睡眠、唤醒、终止

  • static void sleep(long millis):让当前线程进入阻塞状态,放弃当前cpu执行权,让给其它线程使用(线程睡眠);
  • void interrupt():终止线程睡眠(并不是终断线程);
  • void stop():强行结束线程(已弃用,因为当内存中的数据还没有保存就强行结束线程的执行,可能会丢失数据)。

例:

package com.dh.thread;

public class Thread06 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyThread06());
        t.start();
        //在执行start()之后会执行t线程的run()
        //在输出1-4后,控制台会间隔5秒再输出5-9
        try {
            //此时想不间隔5s,而是间隔3秒就输出5-9
            //等待3s
            Thread.sleep(1000 *3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //以异常处理机制的形式唤醒t线程,此时run()会继续执行
        t.interrupt();
        //如果是stop(),则run()不会再继续执行了,即不会输出5-9了
//        t.stop();
    }
}

class MyThread06 implements Runnable{

    @Override
    public void run() {

        for (int i = 1; i < 10; i++) {
            //当i为5的倍数的时候睡眠5s
            if(i % 5 == 0){
                try {
                    //sleep会抛出异常
                    //这里不能使用throws方法
                    //因为Thread类中的run()没有抛出异常
                    //所以不能违反重写的原则:子类抛出的异常不能大于父类抛出的异常
                    Thread.sleep(1000 * 5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(i);
        }
    }
}

结果:

1
2
3
4
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at com.dh.thread.MyThread06.run(Thread06.java:36)
	at java.base/java.lang.Thread.run(Thread.java:834)
5
6
7
8
9

若不想输出异常信息则注释掉e.printStackTrace();即可。

合理终止一个线程:

package com.dh.thread;

public class Thread07 {

    public static void main(String[] args) {
        MyThread07 mt = new MyThread07();
        Thread t = new Thread(mt);
        t.start();
        try {
            //睡眠3s
            Thread.sleep(1000 * 3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //然后将flag设置为false,结束进程
        mt.flag = false;
    }
}

class MyThread07 implements Runnable {

    boolean flag = true;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (flag) {
                System.out.println(i);
                try {
                    //每输出一个数字睡眠1s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                return;
            }
        }
    }
}

结果:

0
1
2

Process finished with exit code 0

t线程在3s之后就终止了。

(4)线程调度(了解即可)

线程的调度模型有两种:

抢占式:哪个线程的优先级高,抢到cpu时间片的概率就相对高一些(Java线程的调度模型就是抢占式);
均分式:不管优先级如何,每个线程平均的分配cpu时间片。

Thread类中有三个与线程优先级相关的静态常量:

public static final int MIN_PRIORITY = 1;	//最低优先级
public static final int NORM_PRIORITY = 5;	//默认优先级
public static final int MAX_PRIORITY = 10;	//最高优先级

也有一些与线程调度有关的方法:

  • void setPriority(int newPriority) :设置线程的优先级;

  • int getPriority(int newPriority) :获取线程的优先级;

  • static void yield() :暂停当前正在执行的线程对象,让给其它线程(运行状态--->就绪状态);

  • void join() :合并线程。

例:

package com.dh.thread;

public class Thread08 {

    public static void main(String[] args) {
        System.out.println(Thread.MIN_PRIORITY);
        System.out.println(Thread.NORM_PRIORITY);
        System.out.println(Thread.MAX_PRIORITY);

        Thread t = new Thread(new MyThread08());
        t.start();
        //设置当前线程优先级
        t.setPriority(8);
        //获取当前线程优先级
        int priority = t.getPriority();
        System.out.println(priority);
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程"+i);
        }
        //
        try {
            //主线程将等待t线程执行完毕,才会继续向下执行
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //一定是在子线程的run()全部执行完毕之后才会输出
       System.out.println("------------主线程----------------");
    }
}

class MyThread08 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("子线程"+i);
            if(i%2 == 0){
                //当i为2的倍数时,t线程将让出cpu的执行权
                Thread.yield();
            }
        }
    }
}

结果:

1
5
10
8
主线程0
子线程0
主线程1
主线程2
主线程3
主线程4
主线程5
主线程6
主线程7
子线程1
主线程8
子线程2
主线程9
子线程3
子线程4
子线程5
子线程6
子线程7
子线程8
子线程9
------------主线程----------------

虽然会因为优先级的大小和yield()礼让会影响到cpu的抢占情况,但是优先级和yield()礼让并不完全就是可以起决定性的作用,由上述结果就可以看出了。

posted @ 2021-02-23 20:11  deng-hui  阅读(183)  评论(0)    收藏  举报