Java基础知识之线程的生命周期及相关面试题

一.线程的生命周期:
(1)生命周期:
一个事物从出生的那一刻开始到最终死亡中间的整个过程.
在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态/中年状态/老年状态…).
线程也是有生命周期的,也是存在不同的状态的,状态相互之间的转换.

(2)API中的定义:
在这里插入图片描述
(3)图形表示:
在这里插入图片描述

1:新建状态(new) 使用new创建一个线程对象,仅仅在堆中分配内存空间,在调用start方法之前.新建状态下,线程压根就没有启动,仅仅只是存在一个线程对象而已.Thread t = new Thread();//此时t就属于新建状态当新建状态下的线程对象调用了start方法,此时从新建状态进入可运行状态.线程对象的start方法只能调用一次,否则报错:IllegalThreadStateException.
2:可运行状态(runnable) 分成两种状态,ready和running。分别表示就绪状态和运行状态。就绪状态:线程对象调用start方法之后,等待JVM的调度(此时该线程并没有运行).运行状态:线程对象获得JVM调度,如果存在多个CPU,那么允许多个线程并行运行.
3:阻塞状态(blocked) 正在运行的线程因为某些原因放弃CPU,暂时停止运行,就会进入阻塞状态.此时JVM不会给线程分配CPU,直到线程重新进入就绪状态,才有机会转到运行状态.阻塞状态只能先进入就绪状态,不能直接进入运行状态.阻塞状态的两种情况:1):当A线程处于运行过程时,试图获取同步锁时,却被B线程获取.此时JVM把当前A线程存到对象的锁池中,A线程进入阻塞状态.2):当线程处于运行过程时,发出了IO请求时,此时进入阻塞状态.
4. 等待状态(waiting) (等待状态只能被其他线程唤醒):此时使用的无参数的wait方法,当线程处于运行过程时,调用了wait()方法,此时JVM把当前线程存在对象等待池中.
5:计时等待状态(timed waiting) (使用了带参数的wait方法或者sleep方法) 1):当线程处于运行过程时,调用了wait(long time)方法,此时JVM把当前线程存在对象等待池中. 2):当前线程执行了sleep(long time)方法.
6:终止状态(terminated) 通常称为死亡状态,表示线程终止.1):正常执行完run方法而退出(正常死亡).2):遇到异常而退出(出现异常之后,程序就会中断)(意外死亡).-线程一旦终止,就不能再重启启动,否则报错(IllegalThreadStateException).在Thread类中过时的方法(因为存在线程安全问题,所以弃用了):void suspend() :暂停当前线程void resume() :恢复当前线程 void stop() :结束当前线程

面试题:.线程的状态有哪些?状态的转移分别依赖什么方法?
答:所有的状态都是和可运行状态(runnable)进行转移的
1:新建状态(new)(调用了start方法进入可运行状态)
2:可运行状态(runnable)
①此时使用的无参数的wait方法,进入等待状态(waiting)
②(使用了带参数的wait方法或者sleep方法,进入计时等待状态
3:阻塞状态(blocked)
4. 等待状态(waiting)(只能被其他线程使用notify方法或notifyAll方法唤醒进入可运行状态)
5:计时等待状态(timed waiting)(规定的时间参数时间到了)
6:终止状态(terminated)

二线程的休眠:
线程休眠:让执行的线程暂停一段时间,进入计时等待状态。
方法:static void sleep(long millis)
调用sleep,当前线程放弃CPU,在指定时间段之内,sleep所在线程不会获得执行的机会。
此状态下的线程不会释放同步锁/同步监听器.
该方法更多的用于模拟网络延迟,让多线程并发访问同一个资源的错误效果更明显.
在开发中也会故意使用该方法

三.联合线程(join)
线程的join方法表示一个线程等待另一个线程完成后才执行。join方法被调用之后,线程对象处于阻塞状态。
也把这种方式称为联合线程,就是说把当前线程和当前线程所在的线程联合成一个线程。

class join extends Thread{
    @Override
    public void run() {
        for(int i =0;i<50;i++){
            System.out.println("join"+i);
        }
    }
}
public class JoinDemo {
    public static void main(String[] args) throws InterruptedException {
        join join = new join();
        for(int i =0;i<50;i++){
            if(i==10){
                join.start();
            }
            if(i==20){
                join.join();
            }
            System.out.println("main"+i);
        }
    }
}

四.后台线程:
在后台运行的线程,其目的是为其他线程提供服务,也称为“守护线程"。JVM的垃圾回收线程就是典型的后台线程。
特点:若所有的前台线程都死亡,后台线程自动死亡,前台线程没有结束,后台线程是不会结束的。
测试线程对象是否为后台线程:使用thread.isDaemon()。
前台线程创建的线程默认是前台线程,可以通过setDaenon(true)方法设置为后台线程,并且当且仅当后台线程创建的新线程时,新线程是后台线程。
设置后台线程:thread.setDaemon(true),该方法必须在start方法调用前,否则出现IllegalThreadStateException异常。

五.定时器和线程组
在JDK的java.util包中提供了Timer类,可以定时执行特定的任务.
TimerTask类表示定时器执行的某一项任务.
常用方法:
schedule(TimerTask task,long delay,long period):安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
schedule(TimerTask task,long delay): 安排在指定的时间执行指定的任务

public class TimerDemo {
    public static void main(String[] args) {
        System.out.println("begin....");
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(new Date().toLocaleString());
            }
        },3000,1000);
    }
}

输出结果:
在这里插入图片描述
ThreadGroup类表示线程组,可以对一组线程进行集中管理.
用户在创建线程对象时,可以通过构造器指定其所属的线程组.
Thread(ThreadGroup group,String name);
如果A线程创建了B线程,如果没有设置B线程的分组,那么B线程加入到A线程的线程组.
一旦线程加入某个线程组,该线程就一直存在于该线程组中直到线程死亡,不能在中途修改线程的分组.
当Java程序运行时,JVM会创建名为main的线程组,在默认情况下,所有的线程都该改线程组下.

发布了99 篇原创文章 · 获赞 2 · 访问量 2614

猜你喜欢

转载自blog.csdn.net/weixin_41588751/article/details/105229730