Java 中 Thread类的基本用法

本文详细介绍了Java中线程的创建,包括通过继承Thread类和实现Runnable接口两种方式,以及使用匿名内部类和lambda表达式的简化写法。还讨论了线程的启动、休眠、中断和等待方法的使用,以及线程的不同状态。文章通过示例代码展示了线程操作的关键点,并比较了不同方法的差异。
摘要由CSDN通过智能技术生成


线程的创建

Thread类的构造方法

在这里插入图片描述

继承Thread类

class ThreadTest extends Thread {
    @Override
    public void run() {
    	// 重写run方法 
        // 线程运行的代码
        System.out.println("继承Thread类来创建一个线程类");
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        // 创建线程实例
        ThreadTest t = new ThreadTest();
        // start方法启动线程
        t.start();
    }
}

使用匿名内部类创建 Thread 子类对象

public static void main(String[] args) {
    // 创建线程实例
    Thread t = new Thread() {
        @Override
        public void run() {
            // 线程运行的代码
            System.out.println("匿名内部类");
        }
    };
    
    // start方法启动线程
    t.start();
}

Runnable 接口

class RunnableTest implements Runnable {
    @Override
    public void run() {
        // 线程运行的代码
        System.out.println("实现Runnable接口");
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        // 创建线程实例
        Thread t = new Thread(new RunnableTest());
        // start方法启动线程
        t.start();
    }
}

使用匿名内部类创建 Runnable 子类对象

public static void main(String[] args) {
    // 创建线程实例
    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
        	// 线程运行的代码
            System.out.println("匿名内部类");
        }
    });
    // start方法启动线程
    t.start();
}

lambda表达式简化匿名内部类

public static void main(String[] args) {
    // 创建线程实例
    Thread t = new Thread(() -> {
        // 线程运行的代码
        System.out.println("lambada");
    });
    // start方法启动线程
    t.start();
}

两种写法的区别

继承Thread类, this表示当前线程对象的引用
实习Runnable接口, this表示Runnable对象的引用

class ThreadTest extends Thread {
    @Override
    public void run() {
        System.out.println(this.toString());
    }
}
class RunnableTest implements Runnable {
    @Override
    public void run() {
        System.out.println(this.toString());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        ThreadTest t1 = new ThreadTest();
        Thread t2 = new Thread(new RunnableTest());
        t1.start();
        t2.start();
    }
}


在这里插入图片描述

Thread类常见的属性和方法

常见属性

在这里插入图片描述

  1. ID是线程的唯一标识
  2. 名称方便我们调试,在创建线程时可以命名
  3. 状态标识线程当前情况
  4. 优先级高的线程理论上优先调度
  5. 所有前台线程结束后,进程才会结束,后台线程不会影响进程的结束
  6. 是否存活,线程的 run 方法是否执行结束,从调用 start 开始,到 run 方法执行结束,都是存活的(除了NEW 和 TERMINATED 状态)

线程的启动

我们通过重写 run 方法创建了线程对象后, 这个线程并没有开始运行,
调用 start 方法, 才真正的在操作系统底层创建了线程并运行run中的代码

重写 run 方法就相当于安排了一个任务
创建线程对象就相当于安排人来做这个任务
调用 start 这个人才真正行动起来

线程的休眠

sleep方法, 是Thread类中的静态方法

public static void main(String[] args) {
    Thread t = new Thread(() -> {
         while (true) {
             System.out.println("hello");
             try {
             	// 运行到这里时, 线程休眠1000ms
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
    });

    t.start();
}

线程的中断

  1. 使用自定义变量作为标志位
public class ThreadDemo {
    // volatile 这个关键字与线程安全有关
    public static volatile boolean flg = false;
    // 因为我们用匿名内部类的方式创建线程对象
    // 由于匿名内部类变量捕获问题(捕获的变量必须是final修饰的,或不会修改值的变量)
    // 所以这个标志位必须是成员变量

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
             while (!flg) {
                 System.out.println("hello");
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
            System.out.println("线程运行结束");
        });
        // 启动线程
        t.start();
        Thread.sleep(3000);
        // 3秒后,修改标志位,中断线程
        flg = true;
    }
}

在这里插入图片描述

  1. 使用Thread类中内部的方法
    在这里插入图片描述
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(() -> {
        // Thread.currentThread() 获取当前线程对象的引用
        while (!Thread.currentThread().isInterrupted()) {
        // while (!Thread.interrupted()) { 
        // 两个 while 条件都可以
             System.out.println("hello");
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
                 //break;
             }
         }
        System.out.println("线程运行结束");
    });
    // 启动线程
    t.start();
    Thread.sleep(3000);
    // 3秒后,设置标志位
    t.interrupt();
}

在这里插入图片描述

我们看运行结果可以发现,这个线程抛出异常后并没有中断,这是因为线程调用 wait/join/sleep 等方法而阻塞挂起时,interrupt 方法抛出异常唤醒阻塞状态,然后这几个方法会清除标志位,所以回到 while 条件时,标志位已经被清除了,可以在 catch 中加入 break 跳出循环

这种写法即使在阻塞状态也能唤醒阻塞并中断线程,而第一种写法要等阻塞状态结束才中断线程。

线程的等待

在这里插入图片描述

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // t线程休眠两秒
            System.out.println("t线程运行结束");
        });
        // 启动t线程
        t.start();

        // t.join();
        // main 线程调用 t.join
        // 意思是让 main 线程等待 t 线程结束, 再往下执行
        t.join();
        System.out.println("main线程运行结束");
    }

在这里插入图片描述

线程的状态

  • NEW:安排了工作, 还未开始行动,创建了线程对象,还未调用start。
  • RUNNABLE: 可工作的。又可以分成正在工作中和即将开始工作。
  • BLOCKED:等待锁引起的阻塞状态。
  • WAITING::等待唤醒,由 wait ,join等方法引起的。
  • TIMED_WAITING:等待唤醒,但是设置了时限,sleep,join(有参数的)等方法引起的。
  • TERMINATED:工作完成了(run 方法执行结束)。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值