系列文章目录
🌈座右铭🌈:人的一生这么长、你凭什么用短短的几年去衡量自己的一生!
💕个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C++,自顶向下看Java-CSDN博客
❤️相关文章❤️:清灵白羽 漾情天殇-CSDN博客
目录
系列文章目录
前言
一、Thread构造方法
1、Thread():
2、Thread(Runnable target):
拓展:
1、Thread.sleep():
2、sleep为什么要捕获异常:
3、捕获异常之后呢?
1、提供线程中断的机制
2、保留中断状态
3、提供了可靠的中断相应机制
4、线程收到异常之后会做什么呢?
1、恢复中断状态、
2、根据实际需求进行是当的清理工作
补充
3、Thread(Runnable target, String name)
二、其它方法
前言
这篇文章我来为大家详细地介绍一下Thread类的常见的方法,以及线程的一些相关操作,当中包括如何中止线程、等待线程。
一、Thread构造方法
在Java当中Thread类是用于创建和操作线程的主要类之一,Thread类的常见构造方法如下:
1、Thread():
这是Thread类的默认构造方法,他创建一个新的线程对象,但是如果我们不指定线程的执行任务,它将不会进行任何操作。
public class Main { public static void main(String[] args) { Thread thread = new Thread(); thread.start(); } }
2、Thread(Runnable target):
这个构造方法接受一个实现了Runnable接口的对象作为参数,通过这样的方法我们可以在新线程当中执行实现了Runnable接口的对象的run()方法。
Thread类是Java当中用于创建和管理线程的类,每个线程都是通过Thread类的实例表示的,Runnable接口是一个功能性接口,它只包含了一个抽象方法run(),当一个类实现了Runnable接口并且提供了run()方法的具体实现的时候,该类的实例就可以被传递给Thread类的构造方法,这个实现了Runnable接口的类通常包含了需要在新线程当中执行的代码。
这个构造方法接受一个实现了Runnable接口的对象作为参数,当创建一个新的Thread实例的时候,可以通过这个构造方法指定该线程要执行的代码,而这段代码通常就是传递进来的RUnnable对象的run()方法。
为什么要采用这样的方式呢,因为我们可以将不同的任务封装在实现了Runnable接口的类的实例当中,并且将这些任务交给Thread对象执行,从而实现多线程编程,这种方式比直接拓展Thread类更加灵活,因为一个类只能直接继承一个父类,但是可以实现多个接口,因此使用Runnable接口可以更好地支持代码的复用和组合。下面我为大家用代码来进行演示:
class MyTask implements Runnable{ @Override public void run() { for (int i = 0;i < 5; i++){ System.out.println("Thread running"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class Main { public static void main(String[] args) { MyTask myTask = new MyTask(); Thread thread = new Thread(myTask); thread.start(); for (int i = 0;i < 5;i++){ System.out.println("主线程正在执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
拓展:
1、Thread.sleep():
这个方法会让当前线程休眠指定的时间,所谓的当前线程是指调用这个sleep方法的线程,例如如果我们在main方法也就是主线程当中调用这个方法就是让主线程进入休眠,如果我们在自己定义的实现了Runnable接口的类当中调用了这个方法就是新的线程在休眠。
2、sleep为什么要捕获异常:
不仅仅是sleep()方法,Thread类当中几乎所有的方法都需要捕获异常,或者抛出异常来处理这个问题,包括我们后需要讲到的join(),wait()方法都需要这样做,那么这是为什么呢?这是因为在Java当中线程在休眠的时候是看可以被打断的,那么这个时候sleep就会发出'InterruptedException'异常来提醒线程已经被中断,因此在使用Thread.sleep()方法的时候需要处理这个异常,通常的做法是使用try-catch块进行环绕并进行相应的处理,比如恢复中断状态或者执行其它逻辑,在我为大家写的示例代码当中即使我们没有明确的中断线程的代码,但是为了保持良好的编码习惯,我们依然捕获了'InterruptedException'异常,这样做的好处是即使未来我们对线程进行了中断操作,代码也已经准备好了处理这种情况,提高了代码的健壮性和可维护性,有很多小伙伴在初学的时候不明白为什么这里一定要进行异常处理,希望我的观点可以帮助到大家。
3、捕获异常之后呢?
Thread这个类在设计的时候让Thread.sleep()抛出'InterruptedException'异常的主要目的是为了提供一种机制来响应线程的中断请求,Java中的线程中断机制允许一个线程中断另外一个线程的执行,当一个线程调用另一个线程的'interrupted'方法的时候,目标线程也就是被中断的线程就会收到一个中断请求,如果这个时候目标线程正在进行sleep(),wait(),join()方法当中休眠那么这个时候中断机制会将这个线程强制唤醒,并且唤醒之后收到一个'InterruptedException'异常信息。
1、提供线程中断的机制
通过抛出异常,允许线程在休眠期间被中断,使得线程可以在收到中断请求以后做出相应的处理,例如终止执行,清理资源等。
2、保留中断状态
当'InterruptedException'异常被捕获之后通常的做法是在catch块当中处理异常并且恢复线程中的中断状态,以便其它部分的代码可以检查到线程被中断,并且采取相应的行动。
3、提供了可靠的中断相应机制
通过抛出异常,确保了即使线程处于休眠状态,也能够及时响应中断请求(因为它会被立刻唤醒,这一点上面我们已经讲过了,这里就不再重复了),而不会无限地等待,这样可以使得多线程程序更加可靠和健壮。
4、线程收到异常之后会做什么呢?
1、恢复中断状态、
在catch块中使用‘Thread.currentThread().interrupt()’(这行代码我刚才的实例里面没有讲到,后面会为大家讲到。所以这里大家只做了解)来重新设置中断状态,以便其它部分的代码能够检查到线程是否被中断。
2、根据实际需求进行是当的清理工作
例如释放资源管理连接等,然后再根据业务的逻辑决定这个线程是否要继续执行,或者直接终止线程的执行不再被调用。
补充
我相信有很多小伙伴不太明白关于我上面讲到的关于恢复线程中断状态的概念,我在这里特别补充一下,线程中断状态是一个标志位,是线程TCB(线程控制块)内部自己维护的一个标志位用于表示线程是否被中断,当目标线程被中断的时候,中断状态就会被设置为true(初始状态为false),当线程在阻塞状态下(比如调用sleep、join等方法的时候)被中断的时候,会抛出'InterruptedException'异常,并且在抛出异常之前Java会清楚线程的中断状态,将中断状态重新设置为false,
因此在处理这个异常的时候,通常需要更新设置线程的中断状态,以便将中断信息传递给更高层的调用栈,catch块当中的Thread.currentThread().interrupt()’会将线程的中断状态设置为之前的值,如果之前是true那么就设置为true如果之前是false亦然,在抛出异常之前清楚中断状态时为了让线程在异常处理之后继续执行,不会误认为被中断过,如果不清理中断状态,即使线程处理了’InterruptedException‘这个异常,但是在异常处理之后线程的中断状态仍然为true,我们要知道线程被中断一定会伴随着一系列的中断处理操作(这个我之前的文章里面有详细讲过这里就不一一介绍了)这样子的话会进行不必要的处理操作,所以在异常抛出之前就会清除中断状态保证异常是真正被中断的时候抛出,这是为了线程在异常处理之后能够正确地继续执行。
我这里还要强调一点不要把清除中断状态和恢复中断状态搞混,清除中断状态是在抛出异常之前系统自动进行的,恢复中断状态是需要在catch块当中手动进行的,恢复中断状态是为了中断信息得以继续传递,通过清除线程的中断状态并且在适当的时候恢复它,使得线程可以在异常处理后继续执行,并且其他部分的代码可以根据需要处理中断请求。(这部分内容作为了解即可)
3、Thread(Runnable target, String name)
这里其实就是给线程起一个名字,内容很简单直接为大家用代码演示。
public class Main { public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0;i < 5;i++){ System.out.println(Thread.currentThread().getName() + "running task"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }; Thread thread = new Thread(runnable,"Thread-1"); Thread thread1 = new Thread(runnable,"Thread-2"); thread1.start(); thread.start(); } }
Thread主要的几个构造方法就为大家介绍到这里,
二、其它方法
后续的方法下一篇文章接着为大家介绍,希望这篇文章能够让你有所收获,我们明天再见!