多线程 六种状态以及生命周期

1. 守护线程Daemon

什么是守护进程?

守护线程:也叫后台线程,脱于控制终端,用来服务用户线程。例如GM垃圾回收 处理后台的工作的线程

用户线程:一般用户执行的线程。

t1.setDaemon(Boolean b);设置线程为守护线程,true 即设置为守护线程 ,false 非守护线程,默认为false

注意:setDaemon方法只能线程启动之前使用,如果对于一个线程已经死亡或者未启动,那么设置setDaemon会抛出IllegalThreadStateException

t1.isDaemon() 获取当前线程是否为守护线程。

守护线程的生命周期

依赖于用户线程,当用户线程存在,守护线程就会存在,反之,用户线程不存在时,守护线程就会消亡

为什么会有守护线程?

守护线程具有自动结束生命周期的特征,当用户线程全部处于终止状态,只剩下守护线程,那么JVM会退出,守护线程自动结束。

假设GM是非守护线程,主函数main结束工作,但JVM无法结束工作,因为GM还在正常工作。

什么时候需要守护线程?

它也叫:后台线程,它可以经常用作执行一些后台任务,当关闭JVM时。希望自动关闭某些线程,则可以将这些线程设置为守护线程。

2. 线程的生命周期

       State枚举类
         NEW, 线程开始
        
       RUNNABLE,运行和就绪
        
        BLOCKED,阻塞状态
        
        WAITING,

        TIMED_WAITING,

        TERMINATED;终止

new:新建状态

使用new’创建线程处于新建状态,此时和其他Java对象一样在Java堆中分配内存,在这种状态下,使用**getState()**可以获取线程的状态。

Runable:就绪状态/运行状态

在Java中Runable状态表示正在占用cpu或者等待cpu资源

在操作系统中将Java的Runable状态分为两个状态:RunableRunning状态。

1.Runable: 就绪状态

当线程被创建后,调用**start()**方法,线程就处于就绪状态,当其他条件都满足时,可等待CPU的使用权

2.Running:运行状态

在运行状态的线程即得到CPU的使用权,执行线程代码,只能是就绪状态到运行状态

Blocked:阻塞状态

指线程因为某些原因放弃CPU使用权eg:缺少资源 IO,锁等,暂停运行,即处于阻塞状态。

Waiting:等待状态

当前状态,因为线程对象调用了**wait()**方法,JVM就会将线程方法置入等待池中

Timed_Waiting:超时等待

调用**Sleep(long time), join(long time)**会时线程处于睡眠状态

Terminated:终止状态

当线程执行 **run()**方法结尾处,进入终止状态,表示该线程的生命周期结束。

线程状态转化图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pLPlfJqW-1613568140750)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210202200057604.png)]

状态转化的方法

start() 启动新线程

启动一个新线程,必须首先调用,且只能调用一次,不能重复调用

JNI:JAVA NATIVE INTERFICE Java本地方法接口

run():子线程执行体

可重复调用,

不需要单独由对象调用,start方法启动后,会主动调用run方法

直接调用和通过调用start方法调用run的区别:

直接调用: 就是普通方法调用,还是在主线程中调用,而非启动一个子线程

yiled():线程让步

Thread.yiled()

暂停当前线程的执行,让步于其他优先级相同或优先级更高等待的线程获取CPU的调度,若没有优先级相同或更高的线程,则此线程会继续运行

运行——》就绪,等待线程调度,需要注意的是仅仅让出CPU资源

此方法是static方法,直接调用不需要对象

public static native void yield();//直接通过类名调用

注意:1. 调用yiled方法的线程进行让步,OS进行调度的下一个线程会不会是让步的线程? 会的,如果没有大于的等于让步线程的优先级,即会调度让步的线程

 2. 为什么yiled是静态的,而不是通过对象调用?因为让步的线程。不一定处于运行状态的线程。

:因为yiled方法只能是正在执行的线程让出CPU的使用权,假设使用线程对象调用yiled方法,会产生错觉让当前的线程对象让步,当前执行的线程不一定是正在运行的线程,必须是占用CPU的线程

sleep():线程休眠

Thread.sleep()通过类名调用。

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

特点

  1. 线程休眠,调用的线程会进入休眠。
  2. sleep方法是Thread的静态方法
  3. sleep方法可以传入参数,即会有时间限制,时间结束,继续运行。
  4. 在休眠的millis中可以调用**interrupt()**调用,会抛出 InterruptedException的异常中断睡眠。

Join(): 线程合并

t.join()

t.join(long mills)

t.join(long mills,int nanos;)

特点:1. Join方法提供了线程的有序进行,将并发执行合并为串行执行。

在线程A中线程B调用B.join() , 则A线程会在B线程执行完成后执行,按照B,A执行。

join方法的本质 还是 wait()方法进入等待状态 waitting 或 Timed_waiting 状态

  1. join() 和 sleep() 一样被中断会抛出***InterruptedException***的异常。不同的是join会 释放锁,因为调用了wait(),而sleep()会一直保持锁
  2. 子线程结束后,子线程的this.notifyAll()会被调用,join()返回,父线程只要获取到锁和CPU,就可以继续运行下去了。
public final void join() throws InterruptedException {
    
    
    join(0);
}
 public final synchronized void join(long millis)
    throws InterruptedException {
    
    
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
    
    
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
    
    
            while (isAlive()) {
    
    
                wait(0);
            }
        } else {
    
    
            while (isAlive()) {
    
    
                long delay = millis - now;
                if (delay <= 0) {
    
    
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
public final synchronized void join(long millis, int nanos)
    throws InterruptedException {
    
    

        if (millis < 0) {
    
    
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
    
    
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
    
    
            millis++;
        }

        join(millis);
    }

Interrupt():中断线程

t.interrupt()

t.isInterrupt()判断是否处于中断操作

特点

  1. 只能中断处于“阻塞状态”的线程(sleep . wait , join等方法进入阻塞状态。)在当前状态调用 interrupt方法,就会抛出 InterruptedException
  2. 若当前线程是正在运行状态,调用interrupt方法,线程还会继续执行,直到发生sleep . wait , join等方法,才会进入到阻塞状态,继而抛出 InterruptedException来中断阻塞状态。原因是每个线程都有个线程标志位 解释:当调用interrupt方法时,会变更该线程的标志位(1个比特位,0->1) 当线程进入阻塞状态时,会判断标志位是否变更,如果变更,立即终止该阻塞状态,随即抛出异常。
public void interrupt() {
    
    
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
    
    
        Interruptible b = blocker;
        if (b != null) {
    
    
            interrupt0();           // Just to set the interrupt flag  只是设置中断标志2
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}
private native void interrupt0();

3.线程优先级 Priority

t1.setPriority();设置线程优先级
t1.getPriority()获取线程的优先级

    public final static int MIN_PRIORITY = 1;最小优先级
    public final static int NORM_PRIORITY = 5;默认优先级
    public final static int MAX_PRIORITY = 10; 最大优先级
public final void setPriority(int newPriority) {
    
    
    ThreadGroup g;
    checkAccess();
    if (newPriority > MAX_PRIORITY (10|| newPriority < MIN_PRIORITY(1) {
    
    先判断优先级的安全
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
    
    
        if (newPriority > g.getMaxPriority()) {
    
    
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

/**
 * Returns this thread's priority.
 *
 * @return  this thread's priority.
 * @see     #setPriority
 */
public final int getPriority() {
    
    
    return priority;
}

特点

  1. Java中线程的优先级只是它执行的概率比较大,而优先级低的线程并不是没有机会,概率相对低。
  2. 优先级范围 1-10.线程的。
  3. 线程的优先级具有继承性,若线程A内创建线程B,B的优先级会和A的优先级相等。

4.线程调度

用户级调度

调用相应的方法来改变线程的状态而达到线程的调度

  1. 调整线程的优先级
  2. 线程睡眠:sleep
  3. 线程等待:wait
  4. 线程让步:yield
  5. 线程合并:join

系统级调度

FIFO:先进先出算法

SJF:最短作业优先算法

RR:时间片轮转法

HPF:最高优先级算法

一般OS 基于RR 和 HPF 基于时间片的有限级调度。

5.并发与并行概念

并发指的是多个线程操作同一个资源,不是同时执行,而是交替执行,单核cpu,只不过 cpu时间片很短,执行速度很快,看起来同时执行

并行才是真正的同时执行,多核cpu。每一个线程使用一个单独的cpu运行

猜你喜欢

转载自blog.csdn.net/weixin_46078315/article/details/113838380