欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > Review --- 线程基础

Review --- 线程基础

2025/4/3 7:54:50 来源:https://blog.csdn.net/2301_78490414/article/details/146921050  浏览:    关键词:Review --- 线程基础

复习线程内容

​ 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存(程序的指令和数据都是首先加载到内存中的,然后根据需要由CPU从内存中读取指令和数据进行处理。)。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存管理IO的。

​ 当一个程序被执行时,操作系统会创建一个对应的进程来管理这个程序的执行。这个过程中,程序的代码(指令)和数据会被加载到内存中。进程控制块(Process Control Block, PCB)用于存储进程的相关信息,操作系统通过PCB来管理和调度进程。

进程概念

​ 进程是操作系统进行资源分配和调度的基本单位,是程序执行过程中的一个实例。它代表了一个正在运行的程序,并且包含了运行该程序所需的所有资源,包括但不限于内存空间、系统文件、状态信息、处理器状态、堆栈、寄存器值等。

线程概念

​ 线程是进程内部的一个执行路径,是进程内的最小执行单元,是一个独立的任务,是CPU调度和分派的基本单位。

img

创建线程的方法

  1. 类 继承Thread类img

  2. 类 实现Runnable接口 重写public void run(){} new Thread(任务)img

  3. 类 实现Callable接口 重写public T call() throws Exception{}img

  4. 使用线程池创建线程(项目中使用的方法)img

那么Runnable接口 和 Callable接口 有什么区别?

1)Runnable接口run方法没有返回值

2)Callable接口call方法有返回值,返回值类型是泛型,和Future、FutureTask配合可以用来获取异步执行的结果

3)Callable接口的call()方法允许抛出异常;而Runnable接口的run方法的异常只能在内部消化,不能继续上抛(也就是方法签名处不能throws)

在启动线程时候可以使用run方法吗?run方法与start方法有什么区别?

​ 调用run方法和使用普通方法一样,调用一次执行一次。可以多次调用

​ 调用start方法是开启线程的,通过该线程调用run方法执行run方法中所定义的逻辑代码。start方法只能被调用一次。如果尝试再次调用 start() 方法,会抛出IllegalThreadStateException 异常。start 方法内部会调用 run 方法,但这是由 JVM 在新线程中完成的,而不是直接调用。

img


线程常用方法

1. run()
  • 作用:定义线程执行的任务。
  • 使用场景:通常通过重写 Thread 类的 run() 方法或传递一个 Runnable 对象来实现具体任务。
  • 注意:直接调用 run() 不会启动新线程,而是作为普通方法在当前线程中执行。
2. start()
  • 作用:启动一个新线程,并让新线程执行 run() 方法中的任务。
  • 使用场景:用于真正启动线程并实现并发执行。
  • 注意:每个线程只能调用一次 start(),多次调用会抛出 IllegalThreadStateException
3. sleep(long millis)
  • 作用:让当前线程暂停执行指定的时间(毫秒),进入 TIMED_WAITING 状态。
  • 使用场景:用于模拟延迟、定时任务或降低线程资源占用。
  • 注意sleep() 是静态方法,作用于当前线程;不会释放锁。
Thread.sleep(1000); // 当前线程休眠 1 秒
4. join()
  • 作用:让其他线程等待当前线程执行完毕后再继续执行。
  • 使用场景:用于确保某些线程按顺序执行。
  • 变体
    • join(long millis):等待指定时间后继续。
    • join(long millis, int nanos):等待指定时间(精确到纳秒)后继续。
thread.join(); // 主线程等待 thread 执行完毕
5. currentThread()
  • 作用:返回当前正在执行的线程对象。
  • 使用场景:获取当前线程信息,如线程名称、优先级等。
Thread current = Thread.currentThread();
System.out.println("Current thread: " + current.getName());

其他常用方法

6. isAlive()
  • 作用:判断线程是否处于活动状态(即是否已启动但尚未结束)。
  • 返回值true 表示线程正在运行,false 表示线程已经终止。
if (thread.isAlive()) {System.out.println("Thread is still running.");
}
7. interrupt()
  • 作用:中断线程,设置线程的中断标志位为 true
  • 使用场景:用于通知线程停止工作或退出阻塞状态。
  • 注意:线程需要自己检查中断状态并做出响应。
thread.interrupt(); // 中断线程
8. isInterrupted()
  • 作用:判断线程是否被中断。
  • 返回值true 表示线程已被中断,false 表示未被中断。
if (thread.isInterrupted()) {System.out.println("Thread has been interrupted.");
}
9. interrupted()
  • 作用:静态方法,检查当前线程是否被中断,并清除中断状态。
  • 返回值true 表示当前线程被中断,false 表示未被中断。
  • 注意:此方法会清除中断标志位。
if (Thread.interrupted()) {System.out.println("Current thread was interrupted.");
}
10. setPriority(int priority)getPriority()
  • 作用:设置或获取线程的优先级。
  • 取值范围:1 到 10,默认优先级为 5。
  • 注意:优先级高的线程有更大机会被调度,但不保证一定先执行。
thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
int priority = thread.getPriority();    // 获取线程优先级
11. setName(String name)getName()
  • 作用:设置或获取线程的名称。
  • 使用场景:用于标识线程,方便调试。
thread.setName("MyThread");
System.out.println("Thread name: " + thread.getName());
12. yield()
  • 作用:提示线程调度器当前线程愿意让出 CPU 资源,允许其他线程运行。
  • 使用场景:用于优化线程调度,但实际效果依赖于操作系统的实现。
Thread.yield(); // 当前线程让出 CPU
13. getState()
  • 作用:返回线程的状态。
  • 可能值
    • NEW:线程尚未启动。
    • RUNNABLE:线程正在运行。
    • BLOCKED:线程被阻塞。
    • WAITING:线程在等待另一个线程。
    • TIMED_WAITING:线程在等待一段时间。
    • TERMINATED:线程已终止。
Thread.State state = thread.getState();
System.out.println("Thread state: " + state);
14. wait(), notify(), notifyAll()
  • 作用:用于线程间的协作,必须在同步代码块中使用。
    • wait():使当前线程等待,直到其他线程调用 notify()notifyAll()
    • notify():唤醒一个等待的线程。
    • notifyAll():唤醒所有等待的线程。
synchronized (lock) {lock.wait();   // 当前线程等待lock.notify(); // 唤醒一个等待线程
}

补充说明

以上列出的方法是 Java 线程管理中最常用的 API。它们可以分为以下几类:

  1. 线程生命周期相关start(), run(), isAlive(), getState()
  2. 线程调度相关sleep(), yield(), join(), setPriority()
  3. 线程中断相关interrupt(), isInterrupted(), interrupted()
  4. 线程协作相关wait(), notify(), notifyAll()

需要更深入地学习线程管理,建议了解线程池(ExecutorService)、并发工具类(如 CountDownLatchCyclicBarrier)以及锁机制(如 ReentrantLock)。

线程状态(Java线程状态和操作系统线程状态)

Java中线程state: 新建state、可运行(包含就绪和运行)、阻塞state(获取锁失败)、等待state(wait)、含time的等待state(sleep)、死亡state

操作系统中线程state:

​ 创建线程 new Thread()

​ 就绪状态 start() 把线程注册到操作系统

​ 运行状态 获得了cpu的执行权(cpu的时间片)

​ 阻塞状态 sleep() join wait 等待synchronized,期间操作系统就不再调用 等待阻塞动作完成后,再回到就绪状态

​ 死亡状态 任务运行结束 出异常没有处理

新建多个线程后,如何保证按顺序执行?

​ 可以用线程中的join方法解决

在Java中wait方法和sleep方法的不同?

共同点:

放弃cpu使用权进入阻塞状态

不同点:

1.方法归属不同:

  • ​ sleep(long)是Thread的静态方法
  • ​ 而wait(),wait(long)都是Object的成员方法 ,每个对象都有

2.醒来时机不同

  • ​ 执行sleep(long) 和 wait(long) 的线程都会在等待相应毫秒后醒来
  • ​ wait(long) 和 wait() 还可以被 notify 唤醒, wait()如果不唤醒就会一直等待下去
  • ​ 它们都可以被打断唤醒

3.锁特性不同 (warning!!!)

  • ​ wait方法的调用必须先获取 wait 对象的锁,而sleep则没有这个限制
  • ​ wait 方法执行后会释放对象锁, 允许其它线程获得该对象锁 (我放弃 cpu使用权,你们还可以用)
  • ​ 而sleep 如果在synchronized 代码块中执行, 并不会释放对象锁 (我放弃 cpu,你们也用不了)

如何停止一个正在运行的线程?

有三种方法可以停止线程.

  • 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
  • 使用stop方法强行终止(不推荐,方法已作废)
  • 使用interrupt方法中断线程 (有两种方式)

​ 打断阻塞的线程(sleep,wait,join)的线程,线程会抛出InterruptedException异常

​ 打断正常的线程,可以根据打断状态来标记是否退出线程

多线程访问共享数据(竞态条件)

​ 存在资源竞争使用问题,

加锁

​ 使用synchronized关键字修饰代码块和方法

​ 同步锁对象,任意类的对象都可以,但是只能是唯一的一个对象,记录有没有线程进入到同步代码块

​ synchronized (同步锁对象){

​ }

​ synchronized修饰方法时,同步锁对象不需要我们指定

非静态方法,锁对象默认是this

静态方法,锁对象是类的Class对象,类的Class对象只有一个

public synchronized void print(){

}

ReentrantLock类实现

lock();加锁

unlock();释放锁

synchronized与ReentrantLock 区别:

线程通信(生产者,消费者模型)

​ wait() notify() notifyAll() 都只能在同步代码块中使用,调用的对象只能是锁对象

​ sleep()和wait()的区别:

sleep(时间) 休眠指定的时间,时间到了会自动进入就绪状态,期间不会释放锁,sleep是Thread类中的方法

wait() 线程等待,不会自己醒来,需要其它线程唤醒,wait方法是会释放锁的,wait是Object类中的方法

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词