(JAVA)-(多线程)-多线程的生命周期和成员方法

 线程的生命周期

传统线程模式的线程状态

1.新建状态:创建线程对象

2.就绪状态:调用start()方法后,有执行资格没有执行权(抢夺cpu执行权)

3.运行状态:抢到了cpu执行权,运行代码,当cpu执行权被抢走,又回到就绪状态

4.死亡状态:当run方法的内容全部执行完,线程就会死亡,变成垃圾

5.阻塞状态:当遇到sleep或者其他阻塞方法,线程就会等着,没有执行资格也没有执行权

,当sleep的时间到了或者其他阻塞方式结束,又会回到就绪状态。

(JAVA)-(多线程)-多线程的生命周期和成员方法_第1张图片

java.lang.Thread类内部定义了一个枚举类用来描述线程的六种状态:

    public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }

跟传统线程模型中的线程状态不同的是:

  1. 枚举类中没有区分就绪运行状态,而是定义成了一种状态Runnable
    • 因为对于Java对象来说,只能标记为可运行,至于什么时候运行,不是JVM来控制的了,是OS来进行调度的,而且时间非常短暂,因此对于Java对象的状态来说,无法区分。只能我们人为的进行想象和理解。
  2. 传统模型中的阻塞状态在枚举类的定义中又细分为了三种状态的:BLOCKEDWAITINGTIMED_WAITING
    • BLOCKED:是指互有竞争关系的几个线程,其中一个线程占有锁对象时,其他线程只能等待锁。只有获得锁对象的线程才能有执行机会。
    • TIMED_WAITING:当前线程执行过程中遇到Thread类的sleep或join,Object类的wait,LockSupport类的park方法,并且在调用这些方法时,设置了时间,那么当前线程会进入TIMED_WAITING,直到时间到,或被中断。
    • WAITING:当前线程执行过程中遇到遇到Object类的wait,Thread类的join,LockSupport类的park方法,并且在调用这些方法时,没有指定时间,那么当前线程会进入WAITING状态,直到被唤醒。
      • 通过Object类的wait进入WAITING状态的要有Object的notify/notifyAll唤醒;
      • 通过Condition的await进入WAITING状态的要有Conditon的signal方法唤醒;
      • 通过LockSupport类的park方法进入WAITING状态的要有LockSupport类的unpark方法唤醒
      • 通过Thread类的join进入WAITING状态,只有调用join方法的线程对象结束才能让当前线程恢复;

说明:当从WAITINGTIMED_WAITING恢复到Runnable状态时,如果发现当前线程没有得到监视器锁,那么会立刻转入BLOCKED状态。

(JAVA)-(多线程)-多线程的生命周期和成员方法_第2张图片

细节:

1.没给线程设置名字线程也有默认的名字格式Thread-x(x为序号,从0开始)

2.jvm虚拟机启动后会启动多条线程,其中有一条线程就是main线程,作用是调用main方法,并执行里面的代码

3.sleep方法:哪个线程执行到这个方法就会停留对应的时间

 线程的调度

1.抢占式调度:多个线程抢占cpu的执行权,具有随机性

2.非抢占式调度:线程轮流执行

jvm中线程的调度是抢占式调度,优先级越高,抢到cpu的概率越大,Java中的线程分为10档,最低是1,不设置默认是5.

(JAVA)-(多线程)-多线程的生命周期和成员方法_第3张图片

(JAVA)-(多线程)-多线程的生命周期和成员方法_第4张图片

 守护线程

fianal void setDaeom(boolean on)

细节:当非守护线程结束了,守护线程也会陆续结束

    public static void main(String[] args) {
        //1.自己定义一个类继承Thread
   MyThread t=new MyThread();
   MyThread1 t1=new MyThread1();
        t.setName("线程1");
        t1.setName("线程2");
      t.setDaemon(true);//将线程1设置为守护线程
   t.start();
   t1.start();

    }


//线程1
 class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"hello");
        }
    }


//线程2
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"hello");
        }
    }
}

(JAVA)-(多线程)-多线程的生命周期和成员方法_第5张图片

细节:

1.我们可以看到,当非守护线程结束后,守护线程没有立马结束,会运行一小段时间,因为在线程退出的一瞬间,守护线程会抢到一小会cpu执行权

2.thread.setDaemon(true)必须在thread.start()之前设置,否则会抛出一个IllegalThreadStateException异常。

3.正在运行的常规线程不能设置为守护线程。

4.多个线程同时运行,守护线程会等所有线程都运行完停止。

礼让线程

public static void yield()

表示出让当前CPU执行权,从运行状态进入就绪状态

此方法跟sleep方法有点像

关于sleep()方法和yield()方的区别如下:

1.sleep方法暂停当前线程后,会进入阻塞状态,只有当睡眠时间到了,才会转入就绪状态;而yield方法调用后 ,是直接进入就绪状态,完全可能马上又被调度到运行状态。

2.sleep 方法会给其他线程运行的机会,但是不考虑其他线程优先级的问题;而yield 方法会优先给更高优先级的线程运行机会。

3.sleep方法声明抛出了InterruptedException,所以调用sleep方法的时候要捕获该异常,或者显示声明抛出该异常。而yield方法则没有声明抛出任务异常。

public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i+getName()+"hello");
            Thread.yield();
        }
    }
}

能尽量让执行结果均匀一点

插入线程

public final void join();
  t.join();
        for (int i = 0; i < 100; i++) {
            System.out.println(i+"主线程结束");
        }

表示把t线程插入在当前线程之前完成。

你可能感兴趣的:(java,开发语言)