Thread类的run()和start()方法

news/2024/11/22 21:38:51/

文章目录

    • 1. 调用Thread类的start()方法后能否再调用start()方法?
    • 2. run()和start()方法的区别?
    • 3. 由问题2引出,是run()方法中的代码先执行还是当前线程中的代码先执行?

今天同学去面试时遇到了一个问题:一个线程在调用Thread类的start()方法之后,还能不能再继续调用start()方法,由此引起了我的一些思考。

1. 调用Thread类的start()方法后能否再调用start()方法?

答案肯定是不能的
我们来看一下例子:

public class ThreadTest {public static void main(String[] args){Thread thread = new Thread();thread.start();thread.start();}}

运行结果如下:

Exception in thread "main" java.lang.IllegalThreadStateExceptionat java.base/java.lang.Thread.start(Thread.java:794)

再进入start()方法,会发现有一个对线程状态的判断,当线程的状态不为0的时候,就抛出异常。这是因为当一个线程启动时,线程便会由新生状态进入就绪状态,JVM会将线程的状态由0变为1,线程在运行时的状态为2。当再次调用start()方法时,就会发现该线程并非是新生线程,从而抛出异常。

if (threadStatus != 0)throw new IllegalThreadStateException();

另外,我们需要注意一点,start()方法是由synchronized修饰的,所以是线程安全的。

2. run()和start()方法的区别?

该问题可谓是面试中经常会问到的问题,具体测试代码如下:

public class ThreadTest {public static void main(String[] args){System.out.println("main的线程Id:" + Thread.currentThread().getId());Thread thread1 = new Thread(() -> System.out.println("thread1的线程Id:" + Thread.currentThread().getId()));Thread thread2 = new Thread(() -> System.out.println("thread2的线程Id:" + Thread.currentThread().getId()));thread1.start();thread2.run();}}

从执行结果中我们可以发现,thread1的线程Id与主线程的有所不同,而thread2的线程Id与主线程是相同的,所以我们可以判定,start()方法是新起一个线程,而run()方法只是一个普通方法,不会新起线程,而是在当前线程中执行。

main的线程Id:1
thread2的线程Id:1
thread1的线程Id:14

3. 由问题2引出,是run()方法中的代码先执行还是当前线程中的代码先执行?

具体测试代码如下:

public class ThreadTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> System.out.println("thread的线程Id:" + Thread.currentThread().getId()));thread.run();TimeUnit.SECONDS.sleep(10);}}

如果是run()方法中的代码先执行,那么应该是先打印线程Id,然后当前线线程休眠,如果是当前线程中的代码先执行,那么应该是当前线程休眠,而不会打印线程Id。实际我们可以将run()方法看出是一个普通的方法调用,因此当调用run()方法时,会先执行run()方法中的代码。
具体测试结果如下:
在这里插入图片描述


http://www.ppmy.cn/news/768914.html

相关文章

独占锁ReentrantLock原理解析

文章目录 1 基本介绍1.1 为什么要使用ReentrantLock1.2 ReentrantLock的常用方法 2 源码梳理2.1 构造方法2.2 加锁2.3 释放锁 参考 1 基本介绍 ReentrantLock是可重入独占锁,同时只能由一个线程锁持有,如果其他线程想要获取锁,就会被阻塞并放…

Java线程池:基本介绍、源码梳理、注意点

文章目录 1 基本介绍1.1 为什么使用线程池1.2 一个简单的例子1.3 线程池实现类:以ThreadPoolExecutor为例1.3.1 ThreadPoolExecutor的构造方法1.3.2 常用的阻塞队列:1.3.3 常用的拒绝策略:1.3.2 ThreadPoolExecutor的工作模型 1.4 线程池的种…

RabbitMQ学习(二):客户端开发

文章目录 1 直接上代码吧1.1 maven1.2 配置类1.3 生产者测试代码1.4 生产者运行结果1.5 消费者测试代码1.6 消费者运行结果 参考 1 直接上代码吧 本篇文章主要展示一个客户端开发Demo。 1.1 maven maven中需要的配置是直接从官网拷贝的。 <dependency><groupId>…

Redis的基本概念

文章目录 1 为什么使用Redis2 为什么Redis这么快3 Redis命令参考4 Redis的数据结构4.1 string&#xff08;字符串&#xff09;4.2 list&#xff08;列表&#xff09;4.3 hash&#xff08;字典&#xff09;4.4 set&#xff08;集合&#xff09;4.5 zset&#xff08;有序列表&…

RabbitMQ学习(一):基本概念

文章目录 1 为什么使用RabbitMQ2 为什么RabbitMQ这么快3 AMQP介绍3.1 AMQP的核心概念3.2 AMQP分层&#xff1a; 4 RabbitMQ的整体结构4.1 结构图4.2 不同的交换机类型 5 相关命令5.1 服务相关命令5.2 用户相关命令5.3 虚拟主机相关命令5.4 队列相关命令5.5 集群相关命令 参考 1…

Redis如何备份与恢复数据

文章目录 1 数据持久化1.1 快照1.2 AOF1.3 混合持久化1.4 从节点持久化 1 数据持久化 Redis有自己的持久化机制&#xff0c;以防宕机后内存中的数据丢失。当宕机后&#xff0c;便从磁盘恢复内存数据结构。 1.1 快照 Redis是使用COW机制实现快照持久化。 第一步&#xff1a;…

RabbitMQ学习(三):高级特性

文章目录 1 生产端如何可靠地投递消息1.1 消息落库打标1.2 消息延迟投递&#xff0c;通过二次确认回调检查。 2 生产者确认&#xff08;Confirm消息确认机制&#xff09;3 消息的幂等性保障3.1 唯一ID 指纹码 机制3.2 利用Redis的原子性实现 4 Return消息机制5 消息的分发与消…

Spring事务的一些总结

文章目录 1 Transactional 注解特性2 事务的属性3 事务的嵌套4 事务超时设置5 Transaction注解不回滚的可能原因6 事务的基本要素(ACID)7 事务的原理8 数据并发问题9 数据库隔离级别10 Spring隔离级别11 底层所使用的不同的持久化API或框架 1 Transactional 注解特性 可以在整…