首先什么是Thread呢?Thread是创建和管理线程的核心类,下面我将对线程的创建、中断、等待、休眠以及如果获取线程实例做出解释说明
start的介绍
在创建线程之前我们得先要了解一个东西,什么是start?
1.启动线程,调用start()方法实际上是Java虚拟机(JVM)中为该线程分配必要的系统资源
2.调用线程的执行体,start()方法内部会自动调用线程的 run() 方法,这是线程实际执行任务的地方。你无需手动调用 run() 方法,直接调用 start() 方法即可。
线程创建
下面我将介绍两种简单的线程创建方法
继承Thread类
最直接的方法当然是创建一个新的类,并重写其 run() 方法。在 run() 方法中定义线程需要执行的代码。然后创建该类实例并调用start()方法来启动线程
class MyThread extends Thread{
public void run(){
//线程执行的代码
System.out.println(1);
}
}
public class demo8 {
public static void main(String[] args) {
MyThread t = new MyThread();//创建线程实例
t.start();//启动线程
}
}
实现Runnable接口
创建一个类实现Runnable接口,并实现 run() 方法。然后将该类的实例传递给Thread类的构造函数,创建Thread对象,通过调用这个对象的start()方法来启动线程。(如果这里没懂后面代码中还有解释)
class MyRunnable implements Runnable{
public void run(){
System.out.println(1);
}
}
public class demo8 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();//实例化Runnable
Thread t = new Thread(myRunnable);//在Thread类的构造函数中,有一个重载形式
//接受Runnable参数,当你创建Thread对象时,将你的Runnable实现类的实例作为参数
//传递进去,这样做实际上是告诉新线程要执行的任务是什么
t.start();
}
}
线程中断
线程中断是Java中一种协作式的线程停止机制,它允许一个线程向另一个线程发出请求,要求被请求的线程停止当前工作。注意:这个机制并不直接停止线程的执行,而是设置一个中断标志,线程需要主动检查并响应这个中断标志
下面这段代码则是简单的演示了线程中断:
// 创建一个名为Worker的Runnable任务
Runnable worker = new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
// 模拟执行任务
System.out.println("正在执行任务, 迭代次数: " + i);
Thread.sleep(1000); // 模拟耗时操作,且该操作可被中断
// 检查中断状态,如果被请求中断,则退出循环
if (Thread.currentThread().isInterrupted()) {
System.out.println("检测到中断信号,退出循环。");
throw new InterruptedException("中断异常");
}
}
} catch (InterruptedException e) {
// 捕获中断异常,打印信息并重新设置中断状态
System.out.println("线程被中断:" + e.getMessage());
Thread.currentThread().interrupt(); // 重新设置中断标志
}
System.out.println("Worker线程结束");
}
};
Thread thread = new Thread(worker, "WorkerThread");
thread.start(); // 启动线程
try {
// 让主线程等待一段时间后中断worker线程
Thread.sleep(5000); // 主线程等待5秒
System.out.println("主线程请求中断Worker线程");
thread.interrupt(); // 发出中断请求
} catch (InterruptedException e) {
e.printStackTrace();
}
这段代码首先定义了一个实现了Runnable
接口的匿名类,代表一个工作线程的任务。工作线程在运行时会每隔一秒打印一次迭代计数,并模拟耗时操作通过Thread.sleep(1000)
。在循环中,它会检查当前线程是否被中断(通过Thread.currentThread().isInterrupted()
),如果被中断,则抛出并捕获InterruptedException
,同时重新设置中断标志,以便其他地方也能检查到中断状态。
主线程则启动这个工作线程,并在等待5秒后向工作线程发出中断请求。这样,你可以观察到工作线程响应中断并提前结束循环的整个过程。
结合上述代码我们来总结一下:
- 如何中断一个线程,可以调用线程对象的
interrupt()
方法 -
阻塞方法:如果线程在执行
Thread.sleep()
,Object.wait()
,Thread.join()
等可中断的阻塞方法时被中断,这些方法会抛出InterruptedException
,这时线程可以捕获这个异常并据此做出响应。 -
周期性检查:在循环或长时间运行的任务中,应该定期检查
Thread.currentThread().isInterrupted()
,如果返回true
,则表明线程被请求中断,此时线程应该清理资源并尽快结束执行。 -
重置中断状态
当捕获到
InterruptedException
时,需要注意,JVM会自动清除中断状态。如果希望其他地方也能检测到中断请求,应该在catch
块中重新设置中断状态,比如以下代码:
try {
// 可能抛出InterruptedException的代码
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断标志
// 处理中断
}
线程等待
join
- 作用:当前线程等待指定线程终止,可以设置等待时间。如果超过了指定的毫秒数,当前线程将不再等待。
- 参数:
millis
- 等待的时间(以毫秒为单位)。 - 使用场景:当一个线程必须等待另一个线程执行完成才能继续执行时使用。
- 异常:可能抛出
InterruptedException
。
示例代码:
Thread t = new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println("t线程执行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
System.out.println("t线程开始执行");
t.start();
t.join();//主线程等待t线程执行完
System.out.println("t线程执行完毕");
wait
- 作用:使当前线程等待,直到其他线程调用此对象的
notify()
方法或notifyAll()
方法,或者超过指定的等待时间。 - 使用场景:通常与
synchronized
一起使用,用于线程间的同步。 - 参数:无参数版本将一直等待,也可以传入毫秒和纳秒参数指定最长等待时间。
- 异常:可能抛出
InterruptedException
。
示例代码:
final Object lock = new Object();
Thread t = new Thread(()->{
synchronized(lock){
try {
System.out.println("t线程开始等待");
lock.wait();//等待,直到被唤醒
System.out.println("t线程被唤醒");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("线程被中断");
}
}
});
t.start();
Thread.sleep(2000);
synchronized(lock){
lock.notify();//唤醒lock上等待的线程
}
获取线程实例
使用Thread.currentThread()
方法可以获取到当前正在执行代码的线程实例。
代码示例:
Thread current = Thread.currentThread();
System.out.println("当前线程名称: "+current.getName());
//创建并启动一个新线程
Thread myThread = new Thread(()->{
System.out.println("新的线程名称是: "+Thread.currentThread().getName());
},"这个新线程名称可以自己取");
myThread.start();
运行结果: