网站首页 > java教程 正文
目录
Java 通过Thread类为并发编程提供了强大的支持。线程允许我们同时执行多个任务,从而通过有效利用CPU的处理能力来增强应用程序的性能。在本文中,我们将深入研究 Java 中Thread类提供的各种构造函数和方法。
Thread类的构造函数
1.Thread()
构造函数Thread()创建一个新的线程对象。但是如果我们使用此构造函数,则线程不会执行任何代码,直到我们调用其上的start()方法。
2.Thread(String name)
使用这个构造函数,我们可以创建一个线程并直接指定其名称。
3.Thread(Runnable target)
此构造函数允许我们传递一个Runnable对象作为线程的目标。当线程启动时,将调用Runnable对象的run()方法。
4.Thread(Runnable target, String name)
与上一个构造函数类似,这个构造函数也将一个Runnable对象作为目标。此外,我们还可以指定线程的名称,这对于调试和日志记录很有用。
5.Thread(ThreadGroup group, String name)
该构造函数允许我们指定一个线程组。线程组可用于组织和管理线程,但是一般很少用。
6.Thread(ThreadGroup group, Runnable target)
此构造函数允许我们为线程指定线程组以及运行的Runnable对象。
7.Thread(ThreadGroup group, Runnable target, String name)
与前面的构造函数类似,我们可以提供线程组、Runnable对象和线程名称。
8.Thread(ThreadGroup group, Runnable target, String name, long stackSize)
此构造函数允许我们指定线程组、Runnable对象、名称和线程的堆栈大小。
设置和获取线程的名称
Java中,每个线程都有一个名称,这个名称可以是JVM生成的默认名称,也可以是程序员提供的自定义名称。我们可以使用Thread类的以下两个方法获取和设置线程的名称:
- public final void setName(String name)
- public final String getName()
示例代码:
class MyThread extends Thread {
}
class Test {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()); // main
MyThread t = new MyThread();
System.out.println(t.getName()); // Thread-0
Thread.currentThread().setName("softAai Apps");
System.out.println(Thread.currentThread().getName()); // softAai Apps
}
}
如何获取当前正在执行的线程
我们可以使用Thread.currentThread()方法获取当前正在执行的线程对象。此方法返回对当前正在执行线程的Thread对象的引用。使用方法如下:
示例代码:
class MyThread extends Thread {
public void run() {
System.out.println("run method executed by Thread: " + Thread.currentThread().getName());
}
}
class Test {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
System.out.println("main method executed by thread: " + Thread.currentThread().getName());
}
}
//main method executed by Thread: main
//run method executed by Thread: Thread-0
线程优先级
每个线程都有一个优先级,这个优先级可以是JVM生成的默认优先级,也可以是w我们自定义的优先级。线程优先级的有效范围为 1 到 10,其中 1 表示最低优先级,10 表示最高优先级。Thread类提供常量来表示一些标准优先级:
- Thread.MIN_PRIORITY--> 1
- Thread.NORM_PRIORITY--> 5
- Thread.MAX_PRIORITY--> 10
以下是有效的线程优先级:
- 0 → 无效
- 1 → 有效
- 10 → 有效
- Thread.LOW_PRIORITY--> 无效
- Thread.HIGH_PRIORITY--> 无效
- Thread.MIN_PRIORITY--> 有效
- Thread.NORM_PRIORITY--> 有效
如果尝试设置有效范围(1 到 10)之外的线程优先级,则会抛出IllegalArgumentException异常。
下面是设置线程优先级的示例:
Thread t = new Thread();
t.setPriority(7); // Valid
t.setPriority(15); // Throws IllegalArgumentException
默认优先级
主线程的默认优先级是5。但是对于所有其他线程来说,包括我们创建的线程,默认优先级都是从父线程继承的。这意味着子线程将与其父线程具有相同的优先级。
示例代码:
class MyThread extends Thread {
}
class Test {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority()); // 5
// Thread.currentThread().setPriority(15); // RE: IllegalArgumentException
// Thread.currentThread().setPriority(7); // --> line 1
MyThread t = new MyThread();
System.out.println(t.getPriority()); // 5 (if line 1 is commented)
}
}
- Thread.currentThread().getPriority()返回主线程的优先级,默认为5。
- 如果尝试将主线程的优先级设置为有效范围(1 到 10)之外的值,则会抛出IllegalArgumentException异常。
- 当我们创建一个新MyThread对象时,它的优先级将从其父线程继承,在本例中是主线程。因此,t.getPriority()也将返回5。
请记住,如果注释掉设置主线程优先级的第 1 行,子线程仍将从其父线程继承默认优先级 5。
我们再来看一个例子:
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("child thread");
}
}
}
class ThreadPriorityDemo {
public static void main(String[] args) {
MyThread t = new MyThread();
// t.setPriority(10); // Uncomment to set child thread priority to 10
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("main thread");
}
}
}
- 如果取消注释t.setPriority(10);,则将子线程 ( MyThread) 的优先级设置为 10,这是最高优先级。
- 如果不设置优先级,主线程和子线程都将具有默认优先级5。在这种情况下,我们无法确定确切的执行顺序。
- 如果子线程的优先级 (10) 高于主线程 (5),则子线程很可能会先获得 CPU 时间并在主线程之前执行其任务。
- 但是,请务必注意,线程优先级行为在不同平台和 JVM 实现之间可能会有所不同。某些平台可能无法为线程优先级提供适当的支持,即使我们设置了优先级,也会导致不可预测的行为。
暂时阻止线程执行有哪些方式
yield()
yield()方法会导致当前正在执行的线程暂时暂停,以便为具有相同优先级的其他线程提供运行机会。如果没有等待线程或所有等待线程的优先级都较低,则同一线程可以继续执行。但是,如果多个线程以相同的优先级等待,则等待的线程接下来获得机会取决于线程调度程序。yield()方法对线程生命周期的影响在于,它暂时将线程置于可运行状态,允许其他线程运行,但yield线程恢复执行的确切时间取决于线程调度程序。
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Child Thread");
Thread.yield(); // Comment out to observe different behavior
}
}
}
class ThreadYieldDemo {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("main Thread");
}
}
}
- 如果注释掉Thread.yield(),两个线程将同时执行,并且我们无法预测哪个线程将首先完成。
- 如果包含Thread.yield(),子线程将频繁地让出处理器,从而为主线程提供更多执行机会。因此,主线程可能会更频繁地完成其任务。
join()
join()方法等待线程完成其执行。当一个线程调用join()另一个线程时,它会等待指定线程完成执行后再继续执行自己。join()方法有多个重载版本,允许我们指定等待时间的超时持续时间。
public final void join() throws InterruptedException
public final void join(long ms) throws InterruptedException
public final void join(long ms, int ns) throws InterruptedException
每个join()方法都会抛出InterruptedException异常。因此,有必要通过使用try-catch块或通过在方法签名中声明可能抛出的异常类型来处理。
示例代码:
class MyThread extends Thread {
public void run() {
for(int i=0; i<10; i++) {
System.out.println("Seetha Thread");
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
}
}
}
}
class ThreadJoinDemo {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
t.join(); // Commented line 1
for(int i=0; i<10; i++) {
System.out.println("Rama Thread");
}
}
}
- 如果注释掉t.join();,主线程和子线程都会同时执行,我们无法预测确切的输出。
- 如果包含t.join();,主线程将调用子线程t对象join()方法,导致主线程等待,直到子线程完成其执行。因此,输出将由主线程和子线程的交替行组成,主线程等待子线程完成后再完成自己的执行。
让我们讨论另一种场景,子线程使用join()方法等待主线程完成
class MyThread extends Thread {
static Thread mt; // this line holds main thread object in main method
public void run() {
try {
mt.join();
} catch(InterruptedException e) {
}
for(int i=0; i<10; i++) {
System.out.println("child thread");
}
}
}
class ThreadJoinDemo {
public static void main(String[] args) throws InterruptedException {
MyThread.mt = Thread.currentThread();
MyThread t = new MyThread();
t.start();
for(int i=0; i<10; i++) {
System.out.println("main thread");
Thread.sleep(2000);
}
}
}
- 在此示例中,子线程 ( MyThread) 调用主线程对象 (mt ) 上的join()方法。这会导致子线程等待,直到主线程完成执行。
- 主线程由Thread.currentThread()获取,其引用存储在MyThread类的静态变量mt中。
- 子线程启动后,主线程继续执行。它打印“主线程”十次,每个打印语句之间有 2 秒的延迟。
- 同时,子线程由于join()方法而处于等待状态。一旦主线程完成执行,子线程就会恢复并打印“child thread”十次。
- 这可确保子线程等待主线程完成后再继续执行。
join() 发生死锁的情况
情况一:主线程与子线程死锁:
- 如果主线程在子线程对象调用join(),并且子线程同时在主线程对象调用join(),则两个线程将无限期地等待对方完成。这会导致死锁情况,两个线程都无法继续进行。
情况2:同一线程内死锁:
- 如果一个线程自身调用join(),程序就会陷入死锁的情况。线程无限期地等待自身完成,而这种情况永远不会发生,从而导致程序被卡住。
sleep()
如果线程不想在特定时间内执行任何操作,则可以使用sleep()方法。
public static native void sleep(long ms) throws InterruptedException
public static void sleep(long ms, int ns) throws InterruptedException
示例代码:
class SlideRotator {
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 10; i++) {
System.out.println("Slide-" + i);
Thread.sleep(5000);
}
}
}
在上面的示例中,模拟了线程在每张幻灯片显示后暂停 5000 毫秒(5 秒)。这模拟了幻灯片旋转过程,其中每张幻灯片显示 5 秒,然后再移至下一张。
interrupt()
线程可以通过调用线程对象上的interrupt()方法来中断睡眠或等待线程。
class MyThread extends Thread {
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println("I am lazy thread");
Thread.sleep(2000);
}
} catch (InterruptedException e) {
System.out.println("I got interrupted");
}
}
}
class ThreadInterruptedDemo {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
t.interrupt(); // Interrupt the child thread
System.out.println("End of main thread");
}
}
- 在此示例中,main线程通过MyThread调用interrupt()方法来中断该线程。
- 如果第 t.interrupt()行被注释掉,主线程将不会中断子线程。在这种情况下,子线程不间断地执行for循环10次。
- 如果第t.interrupt()行没有被注释掉,主线程会中断子线程。其结果是子线程抛出一个InterruptedException异常,并打印消息“I got interrupted”。
- 无论子线程是否被中断,main线程执行结束时都会打印“End of main thread”消息。
现在,让我们讨论当调用interrupt()方法时线程不处于休眠或等待状态时会发送什么:
- 如果调用interrupt()时线程未处于睡眠或等待状态,则不会立即产生影响。
- 中断调用将排队,直到目标线程进入睡眠或等待状态。
- 一旦目标线程进入睡眠或等待状态,中断调用将立即中断该线程。
- 如果目标线程在其整个生命周期中从未进入睡眠或等待状态,则中断调用将不起作用并且将被浪费。
class MyThread extends Thread {
public void run() {
for (int i = 0; i <= 10000; i++) {
System.out.println("I am lazy thread-" + i);
}
System.out.println("I am entering into sleeping state");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("I got interrupted");
}
}
}
class ThreadSleepDemo1 {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
t.interrupt();
System.out.println("End of main thread");
}
}
- 在这个例子中,main线程启动一个MyThread线程并立即调用interrupt()方法。
- 由于MyThread线程正在执行循环而不处于睡眠或等待状态,因此中断调用不会立即生效。
- 中断调用将排队,直到MyThread线程进入睡眠或等待状态。
- 在这个例子中,MyThread线程最终执行到Thread.sleep(10000)时进入睡眠状态,中断调用立即执行并中断它,并且导致它抛出一个InterruptedException异常.
- 如果MyThread线程从未进入睡眠或等待状态,则中断调用在其整个执行过程中不会产生任何影响。
yield()、join()和sleep()方法之间的区别
yield()方法
- 如果一个线程想要暂停执行,为剩余的相同优先级线程提供机会,可以使用yield()方法。
- yield()方法没有重载。
- yield()方法没有final关键字。
- yield()方法不会抛出InterruptedException异常。
- yield()方法是原生的。
- yield()方法是静态方法。
join()方法
- 如果一个线程想要等待其他线程完成才继续执行,则可以使用join()方法。
- join()有方法重载。
- join()方法有final关键字。
- join()方法会抛出InterruptedException异常。
- join()方法不是原生的。
- join()方法不是静态方法。
sleep()方法
- 如果线程不想在特定时间内执行任何操作,则可以使用sleep()方法。
- sleep()有方法重载。
- sleep()方法不是final关键字。
- sleep()方法会抛出InterruptedException异常。
- sleep(long ms)方法是原生的,sleep(long ms, int ns)方法是非原生的。
- sleep()方法是静态方法。
目录
猜你喜欢
- 2024-10-17 Java|剖析类内的五类成员:属性、方法、构造器、代码块、内部类
- 2024-10-17 C++|构造、析构、成员(静态、非静态)函数、友元、全局函数
- 2024-10-17 JavaScript构造函数和原型:构造函数和原型 原创
- 2024-10-17 灵魂拷问:创建 Java 字符串,用""还是构造函数
- 2024-10-17 dart系列之:dart类中的构造函数(dart命名构造函数)
- 2024-10-17 Java面试题#构造函数和Setter哪种DI方式更好
- 2024-10-17 「php」construct() 函数介绍与使用方法详解
- 2024-10-17 为什么不允许使用 Java 静态构造函数?
- 2024-10-17 关于构造函数的Java面试问题(关于构造函数的java面试问题有哪些)
- 2024-10-17 编程语言Java如何创建对象,看完秒懂
你 发表评论:
欢迎- 07-15采用Oracle OSB总线进行服务注册和接入
- 07-15javaEE 新闻管理系统 oracle11+tomcat6
- 07-15从Oracle演进看数据库技术的发展(oracle数据库发展史)
- 07-15如何升级oracle数据库安全补丁(oraclepsu补丁升级)
- 07-15【权威发布】关于Oracle WebLogic Server未授权远程代码执行高危漏洞的预警通报
- 07-15【mykit-data】 数据库同步工具(数据库表同步工具)
- 07-15[Java速成] 数据库基础,Connector/J、JDBC、JPA的关系(day 7)
- 07-15Google前工程主管“入住”Oracle(google浏览器找不到以前的书签)
- 最近发表
-
- 采用Oracle OSB总线进行服务注册和接入
- javaEE 新闻管理系统 oracle11+tomcat6
- 从Oracle演进看数据库技术的发展(oracle数据库发展史)
- 如何升级oracle数据库安全补丁(oraclepsu补丁升级)
- 【权威发布】关于Oracle WebLogic Server未授权远程代码执行高危漏洞的预警通报
- 【mykit-data】 数据库同步工具(数据库表同步工具)
- [Java速成] 数据库基础,Connector/J、JDBC、JPA的关系(day 7)
- Google前工程主管“入住”Oracle(google浏览器找不到以前的书签)
- Oracle数据库云服务系列新增前所未有的企业级功能
- 直播预告丨如何实现Oracle存储过程到java的一键转化
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)