Java基础夯实——2.5 线程的基本方法

Java 中,线程的基本操作主要依赖于 java.lang.Thread 和 java.lang.Object 类提供的方法。这些方法能够控制线程的创建、运行、中止和通信。

Java 线程的基本方法

  1. start 方法:启动线程。
  2. run 方法:线程执行的逻辑。
  3. sleep 方法:让线程暂停执行一段时间。
  4. wait 方法:让线程等待某个条件。
  5. notifynotifyAll 方法:唤醒等待线程。
  6. yield 方法:让出线程执行权。
  7. interrupt 方法:中断线程。
  8. join 方法:等待另一个线程完成。
  9. setDaemon 方法:设置线程为守护线程。

1. start 方法

  • 作用:用于启动一个线程,并调用线程的 run 方法。
  • 说明:调用 start 方法后,线程进入就绪状态,由 JVM 调度执行。
  • 注意:不能直接调用 run 方法来启动线程,否则它只是在当前线程中执行 run 方法,而不会以并发方式运行。

示例代码:

Thread thread = new Thread(() -> {
    System.out.println("Thread is running...");
});
thread.start(); // 启动线程

2. run 方法

  • 作用:定义线程的执行逻辑。
  • 说明run 方法包含线程的具体操作,但需通过 start 方法才能真正以线程的形式运行。
  • 注意:直接调用 run 方法不会创建新线程。

3. sleep 方法

  • 作用:让当前线程暂停执行一段时间。
  • 特性
    • 属于 Thread 类的静态方法。
    • 不释放锁资源。
    • 抛出 InterruptedException 异常。
  • 用途:用于实现定时或延迟操作。

示例代码:

try {
    Thread.sleep(1000); // 暂停 1 秒
} catch (InterruptedException e) {
    e.printStackTrace();
}

4. wait 方法

  • 作用:让线程进入等待状态,直到其他线程调用 notifynotifyAll 方法。
  • 特性
    • 属于 Object 类,而不是 Thread 类。
    • 必须在同步块或同步方法中调用,否则会抛出 IllegalMonitorStateException
    • 会释放锁资源。
  • 用途:用于线程间的通信。

示例代码:

synchronized (obj) {
    obj.wait(); // 当前线程等待
}

5. notifynotifyAll 方法

  • 作用:唤醒一个或所有正在等待的线程。
  • 特性
    • 属于 Object 类。
    • 必须在同步块或同步方法中调用。
    • 不释放锁,直到当前线程退出同步块。

示例代码:

synchronized (obj) {
    obj.notify(); // 唤醒一个等待线程
}

6. yield 方法

  • 作用:让当前线程暂时放弃 CPU 执行权,使其他线程有机会运行。
  • 特性
    • 是静态方法。
    • 不一定会让出执行权,具体行为依赖于操作系统的线程调度器。
  • 用途:用于优化线程的执行顺序。

示例代码:

Thread.yield();

7. interrupt 方法

  • 作用:中断线程,即改变线程的中断状态。
  • 特性
    • 如果线程正在阻塞(如 sleepwait),会抛出 InterruptedException
    • 如果线程未阻塞,仅会设置中断标志位。
  • 用途:安全停止线程。

示例代码:

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        System.out.println("Thread was interrupted!");
    }
});
thread.start();
thread.interrupt(); // 中断线程

8. join 方法

  • 作用:等待指定线程完成。
  • 特性
    • 会阻塞当前线程,直到目标线程执行完毕。
    • 可指定超时时间。
  • 用途:实现线程的顺序执行。

示例代码:

Thread thread = new Thread(() -> {
    System.out.println("Thread is running...");
});
thread.start();
try {
    thread.join(); // 等待线程完成
} catch (InterruptedException e) {
    e.printStackTrace();
}

9. setDaemon 方法

  • 作用:将线程设置为守护线程。
  • 特性
    • 守护线程会在所有非守护线程结束后自动停止。
    • 必须在调用 start 方法前设置,否则会抛出异常。

示例代码:

Thread thread = new Thread(() -> {
    while (true) {
        System.out.println("Daemon thread running...");
    }
});
thread.setDaemon(true);
thread.start();

sleepwait 的区别

特性sleepwait
所属类ThreadObject
锁状态不释放锁释放锁
用途暂停线程,主要用于时间控制线程间通信
调用位置可在任何地方调用必须在同步块或同步方法中
恢复条件时间结束或被中断notify/notifyAll 唤醒

start 方法和 run 方法的区别

  1. start 方法
    • 用于启动线程,并调用线程的 run 方法。
    • 线程进入就绪状态,由 JVM 调度。
  2. run 方法
    • 包含线程的执行逻辑。
    • 如果直接调用 run 方法,则不会启动新线程,仅在当前线程中执行。

终止线程的 4 种方式

  1. 正常结束:线程执行完毕后自动退出。
  2. 标志位控制:通过一个标志变量来控制线程的运行状态。
    volatile boolean running = true;
    Thread thread = new Thread(() -> {
        while (running) {
            // 执行任务
        }
    });
    running = false; // 停止线程
    
  3. interrupt 方法:通过中断标志位来通知线程停止。
  4. 停止方法(不推荐):调用 stop 方法,直接强制终止线程,可能导致资源释放不完整。

相关问题

1. Java 中的 notify 方法和 notifyAll 方法有什么区别?

notifynotifyAllObject 类的方法,用于唤醒处于等待状态的线程。它们的主要区别如下:

特性notifynotifyAll
唤醒线程的数量唤醒一个等待线程。唤醒所有等待线程。
选择性被唤醒的线程由 JVM 决定(随机选择)。所有线程被唤醒后进入就绪状态,竞争锁。
使用场景适用于有明确线程唤醒逻辑的场景。适用于需要唤醒所有等待线程的场景。
效率可能更高,因为只唤醒一个线程。可能导致线程切换开销增加。

示例代码

synchronized (obj) {
    obj.notify(); // 唤醒一个等待线程
    // 或者
    obj.notifyAll(); // 唤醒所有等待线程
}
  • notify 常用于需要处理特定任务的单线程。
  • notifyAll 常用于广播通知,适合多个线程需同时响应的情况。

2. 守护线程是什么?

为其他线程(用户线程)提供后台服务的线程。当所有用户线程结束运行后,JVM 会自动终止守护线程的运行。

特性

  1. 生命周期依赖用户线程:所有用户线程结束后,守护线程会自动结束。
  2. 主要用于后台任务:如垃圾回收、定时器等。

设置守护线程

使用 setDaemon(true) 方法将线程设置为守护线程,但必须在调用 start 方法之前设置

示例

Thread daemonThread = new Thread(() -> {
    while (true) {
        System.out.println("Daemon thread running...");
    }
});
daemonThread.setDaemon(true); // 设置为守护线程
daemonThread.start();
  1. 守护线程在 JVM 终止时不保证完成其任务。
  2. 不建议将关键业务逻辑放在守护线程中。

3. 如何安全地终止一个线程?

通过标志位控制

线程在运行过程中定期检查一个标志变量,当标志变量被修改时,线程主动退出。

class SafeStopThread extends Thread {
    private volatile boolean running = true;

    public void run() {
        while (running) {
            System.out.println("Thread is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 恢复中断状态
                break;
            }
        }
    }

    public void stopThread() {
        running = false;
    }
}

SafeStopThread thread = new SafeStopThread();
thread.start();
thread.stopThread(); // 安全终止线程

interrupt 方法

interrupt 方法会通知线程中断,通过抛出 InterruptedException 或检查 Thread.isInterrupted() 方法处理终止逻辑。

Thread thread = new Thread(() -> {
    try {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Thread is running...");
            Thread.sleep(1000);
        }
    } catch (InterruptedException e) {
        System.out.println("Thread was interrupted!");
    }
});

thread.start();
thread.interrupt(); // 通知线程中断

使用任务框架(如 FutureExecutorService

通过线程池管理线程,调用 shutdowncancel 方法来终止任务。

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        System.out.println("Task is running...");
    }
});

// 停止任务
future.cancel(true);
executor.shutdown();

结合 join 等待线程结束

通过标志位配合 join 方法,等待线程主动退出后,主线程继续执行

Thread thread = new Thread(() -> {
    for (int i = 0; i < 5; i++) {
        System.out.println("Thread is running...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            break;
        }
    }
});

thread.start();
thread.join(); // 等待线程结束
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值