Thread类及常见方法

本文详细介绍了Java中的Thread类,包括其构造方法、常用属性(如ID、状态、优先级等)、启动线程的start方法、终止线程的方式(中断和标志位)、等待线程的join方法以及获取当前线程引用和休眠功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Thread类是Java中用于创建和管理线程的基类(父类),它提供了一些方法来创建,启动,控制和管理线程,以及获取线程的属性和状态,每个线程都有对应于一个Thread对象,可以通过创建Thread对象,启动一个新的线程,并且在该线程中执行指定的代码.

Thread类的构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
Thread(ThreadGroup group,
Runnable target)线程可以被用来分组管理,分好的组即为线程组
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("My Thread");
Thread t4 = new Thread(new MyRunnable(), "My Thread");

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("hello");
            }
        }, "myThread");
        t.start();
    }

线程是通过start创建的,一个线程的入口方法执行完毕(对于主线程,是main;对于其他的线程,run/lambda),执行完线程的入口函数,线程就会销毁.

Thread类的属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID:线程的唯一标识,不同的线程不会重复
  • 状态:线程当前所处的情况
  • 优先级:优先级的高的会被先调度到,由系统内核来负责
  • 是否后台线程:后台进程不影响进程结束,前台线程,会影响进程结束,如果前台进程没有执行完毕,进程是不会结束的,前台线程结束,那么后台线程就会随之结束,创建的线程默认是前台线程,通过setDaemon显式的设置成后台.
 public static void main(String[] args) {
        Thread t = new Thread(()-> {
           while (true) {
               System.out.println("hello Thread");
           }
        },"Mythread1");
        t.setDaemon(true);//转化为后台线程
        //前台线程就只剩下main,前台线程结束,那么后台线程就会随之结束
        t.start();
    }
  • 是否存活:Thread对象,对应的线程(系统内核中)是否存活,Thread对象生命周期,并不是和系统中的线程完全一致,一般是Thread对象先创建好,再手动调用start,内核才真正创建出线程.简单的理解,就是run方法是否运行结束了.

Thread方法

启动一个线程

start方法就是调用系统的api完成线程创建工作,start方法本身的执行是一瞬间就完成的,只是告诉系统,你要创建一个线程,调用完start完毕之后,代码就会立即继续执行start之后的逻辑.

终止一个线程

一个线程的run方法执行完毕,就算终止了,此处的终止线程,就是想办法,让run能够尽快的执行完毕.
目前常见的两种快速终止线程的方式:

  1. 通过共享的标记来进行沟通
  2. 调用interrupt()方法来通知
//使用自定义的变量作为标志位
public class demo6 {
//如果是成员变量就不触发变量捕获的逻辑了,而是"内部类访问外部类的成员"
    public static boolean isQuit = false;

    public static void main(String[] args) throws InterruptedException {
    //boolean isQuit = false;//局部变量
    //lambda表达式可以捕获到外面的变量
        Thread t = new Thread(()->{
           while (!isQuit) {
               System.out.println("hello");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        });
        t.start();
        //主线程执行其他的逻辑后,要让t线程结束
        Thread.sleep(3000);

        //修改前面设定的标志位
        isQuit = true;
        System.out.println("t 线程终止");
    }
}

如果把isQuit设置为局部变量编译器就会报错,isQuit是跟随main方法销毁,lambda表达式执行时机是更靠后的,这就导致,后续真正执行lambda的时候,局部变量isQuit就可能已经被销毁了,为了解决这一问题,lambda就引入"变量捕获"这样的机制,lambda内部看起来是直接访问外部的变量,其实本质上是把外部的变量复制了一份到lambda里面.就可以解决生命周期的问题了,但是变量捕获这里有个限制,要求捕获的变量得是final(至少看起来是final,代码中没有修改变量,这个变量也可以视为final),如果这个变量想要进行修改,就不能进行变量捕获.java通过复制的方式来实现"变脸捕获"的原因是因为如果外面的代码要对这个变量进行修改,就会出现一个情况:外面的变量变了,里面的没变,代码更容易出现歧义.

//线程终止,使用Thread自带的标志位
public class demo7 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            //Thread提供了静态方法,在哪个线程调用这个方法,就能获取哪个线程的引用
            //Thread.currentThread()获取当前线程的对象(相当于t),
            //但是lambda表达式是在构造t之前就定义好的,编译器看到的lambda里的t会认为这是一个还没初始化的对象
            //isInterrupted()对象内部提供了一个标志位(boolean),true:线程应该要结束 false:线程先不必结束
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                   e.printStackTrace();

                }
            }
        });
        t.start();
        Thread.sleep(3000);
        //把上述的标志位设置成true
        t.interrupt();
    }
}

在这里插入图片描述
t线程正在sleep,其他线程调用interrupt方法,就会强制使sleep抛出一个异常,sleep就被立即唤醒了,sleep在被唤醒的同时,会自动清除前面设置的标志位,如果想继续让线程结束,那么就在catch中加个break即可.

当sleep被唤醒后,可以有以下几种操作方式:

  1. 立即停止循环,立即结束线程
  2. 在catch中执行别的逻辑,之星完毕再结束线程break
  3. 忽略终止的请求,继续循环.

等待一个线程

多个线程是并发执行的,具体的执行过程,都是由操作系统负责调度的,操作系统调度线程的过程,是"随机"的.无法确定,线程执行的先后顺序.等待线程,是一种规划线程结束顺序的手段.

举一个例子:此时有A B两个线程,我们希望B先结束,A后结束,此时就可以让A线程中调用B.join的方法,此时,B线程还没执行完,A线程就会进入"阻塞"(代码不继续往下执行)状态,就相当于给B留下了执行的时间,B执行完毕之后,A再从阻塞状态中回复回来,并且继续往后执行.如果A执行到B.join(等待结束,run方法执行完毕)的时候,B已经之星完了,A就不必阻塞了,直接往下执行就可以了.

public class demo1 {
    public static void main(String[] args) {
        Thread b = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                System.out.println("hello b");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("b 线程结束");
        });
        Thread a = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello a");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                //如果b还没执行完毕,b.join就会产生阻塞的情况
                b.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("a 线程结束");
        });
        a.start();
        b.start();
    }
}

阻塞:让代码暂时不继续执行(该线程暂时不去cpu上参与调度)与sleep不同的是,sleep的阻塞时有时间限制的,而join的阻塞是"死等",为了不让线程死等,我们设定了一个最大的等待时间.

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒

获取当前线程引用

方法说明
public static Thread currentThread();返回当前线程对象的引用
public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
    }
}

休眠当前线程

因为线程的调度是不可控的,所以,这个方法只能保证实
际休眠时间是大于等于参数设置的休眠时间的.比如说sleep(1000)的意思是该线程在1000ms之后,就恢复成"就绪状态",此时就可以随时去cpu上执行了,但不一定是立即马上就去制定.
sleep(0):让当前线程放弃cpu,准备下一轮的调度.

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis毫秒
public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        System.out.println(System.currentTimeMillis());
        Thread.sleep(3 * 1000);
        System.out.println(System.currentTimeMillis());
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值