参考小林coding Home

线程安全在三个方面的体现

  • 原子性:一个或一组操作要么全部执行成功,要么全部不执行
  • 一致性:多个线程访问共享变量,保证所有线程看到的值是一致的。
  • 有序性:程序必须按照代码顺序执行

线程创建的方式

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口与FutureTask
  • 使用线程池

Java线程的状态

NEW:尚未启动的线程状态

RUNNABLE:就绪状态+正在运行状态

BLOCKED:阻塞状态

WAITING:等待状态的线程正在等待另一线程执行特定的操作

TIMED_WAITING:具有制定等待时间的等待状态

TERMINATED:线程完成执行,终止状态

线程状态转换

null

如何停止一个线程

使用方法interrupt()来停止线程。

interrupt不会强制线程立即停止,而是通知这个线程停止,何时停止的决定权在线程本身。

对于休眠,阻塞状态的线程,调用interrupt()*会抛出异常,并设置中断标志位为false。为什么要这样设计? 因为底层休眠或阻塞方法实现通常包含循环检测和等待, 它们每次循环都会检测中断标志。如果你不清除,会导致不停地抛出异常。*

所以使用interrupt()停止线程的最佳实践是,抛出异常时设置中断标志位为false,在处理异常时恢复为true,这样既避免了死循环,也保证了中断状态不会丢失。

下面是代码例子

package org.example.throwable;

public class Worker extends Thread{
    @Override
    public void run() {
        try {
            while (true) {
                System.out.println("线程正在工作");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            // 恢复中断状态
            Thread.currentThread().interrupt();
        }
        
        // 后续代码可以检测中断标志,执行清理
        if (Thread.currentThread().isInterrupted()) {
            System.out.println("检测到中断状态,执行清理工作");
        }

        System.out.println("线程退出");
    }

}

sleep和wait的区别

对比例表:

特性sleep()wait()
所属类Thread 类(静态方法)Object 类(实例方法)
锁释放
使用前提任意位置调用必须在同步块内(持有锁)
唤醒机制超时自动恢复notify()/notifyAll() 或超时
设计用途暂停线程执行,不涉及锁协作线程间协调,释放锁让其他线程工作
  • 所属分类的不同:sleep 是 Thread 类的静态方法,可以在任何地方直接通过 Thread.sleep() 调用,无需依赖对象实例。wait 是 Object 类的实例方法,这意味着必须通过对象实例来调用。
  • 锁释放的情况Thread.sleep() 在调用时,线程会暂停执行指定的时间,但不会释放持有的对象锁。也就是说,在 sleep 期间,其他线程无法获得该线程持有的锁。Object.wait():调用该方法时,线程会释放持有的对象锁,进入等待状态,直到其他线程调用相同对象的 notify()notifyAll() 方法唤醒它
  • 使用条件:sleep 可在任意位置调用,无需事先获取锁。 wait 必须在同步块或同步方法内调用(即线程需持有该对象的锁),否则抛出 IllegalMonitorStateException
  • 唤醒机制:sleep 休眠时间结束后,线程 自动恢复 到就绪状态,等待CPU调度。wait 需要其他线程调用相同对象的 notify()notifyAll() 方法才能被唤醒。notify() 会随机唤醒一个在该对象上等待的线程,而 notifyAll() 会唤醒所有在该对象上等待的线程。

blocked和wait区别

blocked是锁竞争失败后被动触发的状态,wait是人为触发的主动状态。

blocked的唤醒是自动出发的,wait的唤醒需要用特定方法主动唤醒。

blocked开销会比waitng大,因为blocked抢锁失败了,cpu会不断尝试获取锁。

而wait是自己放弃执行并挂起,操作系统会将它移出运行队列,减少调度。

wait状态下的线程怎么切换到running状态

使用notify或者notifyAll

notify是随机唤醒一个调用了wait()线程

notifyAll是唤醒当前等待队列中所有因调用wait()而等待的线程