关于Thread 类及其基本用法

        Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。 要想知道Thread类的基本用法,首先得知道如何创建Thread类,创建Thread类的方法大抵有多种,这里简单的举例比较常用的。

1)继承Thread类,然后像创建普通类一样创建Thread类。

2)实现 Runnable 接口,创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数.

3)匿名内部类创建 Thread 子类对象

4)匿名内部类创建 Runnable 子类对象

5)lambda 表达式创建 Runnable 子类对象

class Student extends Thread{
    @Override
    public void run() {
        System.out.println("haha1");
    }
}
class Teacher implements Runnable{
    @Override
    public void run() {
        System.out.println("haha2");
    }
}
public class Test2 {
    public static void main(String[] args) {
        Student student = new Student();//方法1
        student.start();
        Thread thread2 = new Thread(new Teacher());//方法2
        thread2.start();
        Thread thread3 = new Thread(){
            @Override
            public void run() {
                System.out.println("haha3");
            }
        };//方法3
        thread3.start();
        Thread thread4 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("haha4");
            }
        });//方法4
        thread4.start();
        Thread thread5 = new Thread(() -> {
            System.out.println("haha5");
        });//方法5
        thread5.start();
    }
}

当知道Thread类被创建后,就得知道如何使用Thread类了,首先得知道,start()方法,start()被调用才能创建线程,我们重写的方法run()只是将要被线程执行的逻辑罢了,其次则是Thread的构造方法,从上面的如何创建Thread类,就可以了解到几个Thread的构造方法,首先是典型的没有任何参数的构造方法,方法一和方法三就是,然后则是使用 Runnable 对象创建线程对象 ,方法二,四,五就是(Thread(Runnable target)),当然还有给线程命名的构造方法,毕竟没有给线程命名的话,这调用和调试起来也不太方便(Thread类的对象名不是线程名)(Thread(String name)),最后则是使用 Runnable 对象创建线程对象并且顺便给线程命名的构造方法(Runnable target, String name),这里只说四个并不只有四个,只是其他方法运用较少,这里不做讨论。

        然后则是Thread的常见属性了,Thread的属性较多,这里只做几个较为重要的属性认识。

1)ID:ID 是线程的唯一标识,不同线程不会重复,其获取方法为通过Thread类的对象来获取。

Thread thread6 = new Thread(() -> {
    System.out.println("hehe");
});
thread6.getId();

2)名称:名称是各种调试工具用到,其可以为自己通过创建Thread对象时给的名称name(Thread(String name)),也可以是不给名称由系统默认取名。获取方法为:

thread6.getName();

3)状态:则是线程当前处于的状态,是已完成,还是已创建但没有启动,亦或者是已启动但还没完成的状态等。获取方法则为:

thread6.getState();

4)优先级:事情有轻重缓急,进程也一样,理论上优先级高的线程更容易被调度。获取方法为:

thread6.getPriority();

5)是否为后台线程:关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。获取方法为:

thread6.isDaemon();

6)是否存活:run 方法是否运行结束了,获取方法为:

thread6.isAlive();

7)是否被中断:线程的中断问题,下面我们进一步说明,获取方法为:

thread6.isInterrupted();

关于中断线程,若一个线程已经启动起来了,该怎样让它停下来呢?

目前常见的有以下两种方式:
1. 通过共享的标记来进行沟通
2. 调用 interrupt() 方法来通知
首先是1,怎么通过共享的标记进行沟通呢?,及通过一个变量的变化,来操纵线程里的判断,使之尽早执行完run()。
public static int n = 3;
public static void main(String[] args) {
    Thread thread = new Thread(() -> {
        while (n != 0){
            ;
        }
        System.out.println("haha");
    });
    thread.start();
    n = 0;
}

其次则是2,使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.其Thread.currentThread()表示获取当前的线程,isInterrupted()则可以认为是Thread对象内部提供了一个标志位(bonlean),而isInterrupted()则是获取当前标志位,默认为false,倘若要修改标志位的话,只需要使用Interrupted()方法。

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("haha");
        }
    });
    thread.start();
    sleep(1000);
    thread.interrupt();
}

因此,这里出现的方法也得熟练掌握。

public void interrupt() :中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted() :判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted():判断对象关联的线程的标志位是否设置,调用后不清除标志位
thread 收到通知的方式有两种:
1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通 知,清除中断标志
当出现 InterruptedException 的时候 , 要不要结束线程取决于 catch 中代码的写法 . 可以选择
忽略这个异常 , 也可以跳出循环结束线程 . 否则,只是内部的一个中断标志被设置,thread 可以通过 Thread.interrupted() 判断当前线程的中断标志被设置 (清除中断标志)Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,(不清除中断标志)
这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到。
        下面则简单的介绍线程的常用方法:
1)等待一个线程 -join():当有参数时,则是等待的时长为该参数的毫秒,没有则等待该线程介绍才行,那个对象调用则是等待那个线程。
thread.join();
thread.join(1000);
public void join(long millis, int nanos) ,同理,但可以更高精度
2)获取当前线程引用 public static Thread currentThread(); 返回当前线程对象的引用
3)休眠当前线程:sleep():与join的用法相同,但需要参数并且和join()的参数一样, 有一点要记得,因为线程的调度是不可控的,所以,这个方法只能保证实 际休眠时间是大于等于参数设置的休眠时间的。
至此,关于Thread的简单认识和使用就此结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值