1. 线程启动–start

是Java标准库提供的一个方法。
1.每个Thread对象,都只能start一次。
2. 每次如果想创建一个新的线程,都需要创建1个新的Thread对象(不能重复使用的)
3. start: 是java.lang.Thread 类中,是一个本地(native)方法。作用是启动一个线程,调用系统的api。
run: 是线程的入口方法,无需手动调用。是Runnable接口中的一个抽象方法,也是Thread类的一个普通方法。我们在创建线程的时候,会重写Thread类的run方法,在使用Runnable接口时,实现run方法。

Thread t = new Thread(() ->{
   System.out.println("hello t");
});
t.start();//会启动线程,使线程进入就绪状态

2. 等待线程—join

由于线程是随机调度,并发执行的。 所以,join–等待线程,就能够要求,多个线程之间,结束的先后顺序。

  Thread t = new Thread(() ->{
       for (int i = 0; i < 3; i++) {
            System.out.println("hello thread");
       }
        try {
             Thread.sleep(1000);
        } catch (InterruptedException e) {
              throw new RuntimeException(e);
        }
      System.out.println("t 线程结束");
      });
       t.start();
      t.join();
        System.out.println("hello main");

上述代码,在main线程中,调用t.join,就是让主线程等待t线程。当执行到t.join() 的时候,此时,main线程会“阻塞等待”,一直到t线程执行完毕,join才能继续执行。
join还提供了带参数的版本,指定“超出时间”,即等待的最大时间

t.join(3000);
线程本身的调度是以ms为级别的。相当于等待3秒
如果3秒之内,比如刚过了1秒,线程t就结束了,此时,join就会立即执行,不会等满3秒。
如果t线程超过了3秒,那么join也会继续执行下去,而不会在进行等待了。

3. 获取线程引用

public static Thread currentThread();

获取当前线程的引用。
哪个线程调用了这个方法,返回哪个线程的引用,类似于我们学过的this关键字

4. 休眠当前线程—sleep

sleep:举个例子
比如,我的好朋友A,今天突然说要出差,我就没有办法在约A出来聚会了,即A就不能参与调度了。
类似于sleep

sleep(1000);

1000很有可能会比1000多一点。
当代码调用了sleep,相当于当前线程让出cpu资源,后续等时间到了,操作系统内核,把这个线程重新调度到CPU上,才能继续执行。 时间到了,是允许被调度,而不是立即执行了,至于什么时间执行,还是需要看操作系统的调度器的决定。

sleep(0);

特殊的写法:意味着让当前的线程,立即放弃CPU资源,等待操作系统重新调度。

5. 线程状态

Java线程是对操作系统的线程的封装。

1. NEW

含义 : 当我们创建好线程,即new了个Thread对象,但是还没有start ,即为NEW状态。

 Thread t = new Thread(() ->{
       for (int i = 0; i < 3; i++) {
          System.out.println("hello thread");
       }
       try {
              Thread.sleep(1000);
       } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
           System.out.println("t 线程结束");
  },"t1");
   System.out.println(t.getName() + " " + t.getState());
  //t.start();//还没有启动start

在这里插入图片描述

结果是NEW状态,上述代码,获取当前的线程状态 .getState()。

2. Terminated

含义:操作系统内核中的线程已经结束了,Thread对象还在。相当于“工作都完成了”

    Thread t = new Thread(() ->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello thread");
            }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            System.out.println("t 线程结束");
        },"t1");
        System.out.println(t.getName() + " " + t.getState());// t1 NEW
        t.start();
        //Thread.sleep(2000);
        t.join();
        System.out.println(t.getName() + " " + t.getState()); //t1 Terminated

上述代码,当我们执行完t线程的时候,在最后一行执行的线程状态就是 Terminated

3. runnable

含义: 就绪状态,要么是正在CPU上执行,要么是随时都可以去CPU上执行。

比如,去银行办理业务,你可以是正在安排的服务人员,也可能是正在排队等待服务的人。

Thread t = new Thread(() ->{
    for (int i = 0; i < 3; i++) {
           System.out.println("hello thread");
    }
    try {
         Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println("t 线程结束");
 },"t1");
    t.start();
   System.out.println(t.getName() + " " + t.getState());

runnable就是在启动线程之后,就是正在 CPU 上执行(运行中),也可能在等待 CPU 资源(就绪状态)。

4. time_waiting

指定时间的阻塞,线程的阻塞(不参与CPU调度,不继续执行了),阻塞的时间是有上限的。

、线程是会在Thread.sleep(1000),wait,join 等进行阻塞等待,等待超时会就会自动唤醒。
线程调用 Thread.sleep(1000); 线程进入 TIMED_WAITING 状态 1 秒。

5. waiting

死等,没有超出时间的阻塞等待。是需要其他线程去主动唤醒的。

调用 object.wait();,线程进入 WAITING 状态。

6. blocked

也是一种阻塞状态,比较特殊,由于死锁导致的阻塞。
后续线程安全问题,会进行详细解答。

总结

在深入理解线程状态之后,我们对之后代码的bug就会很好进行调试。可以通过jconsole,查看当前所有的线程。当我们看到线程状态的不同,会有不一样的代码理解:

  1. time_waiting / waiting 怀疑是不是代码的某个方法产生了阻塞,没有即使被唤醒。
  2. block 代码中是否出现死锁,考虑线程安全问题。
  3. runnable 线程本身是没有问题的,考虑某些条件是不是没有触发。
  4. NEW(创建 Thread)→ RUNNABLE(start() 启动,执行 run())→ 若竞争锁失败则进入 BLOCKED → 获取锁后执行 sleep() 进入 TIMED_WAITING → 唤醒后执行 wait() 进入 WAITING → 被 notify() 唤醒后回到 RUNNABLE → run() 执行完毕后进入 TERMINATED。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐