Java中线程的创建与启动

发布时间: 2024-01-16 08:30:32 阅读量: 15 订阅数: 15
# 1. 介绍Java线程 ## 1.1 什么是线程 在计算机科学中,线程是程序中独立执行的最小单位。一个进程由多个线程组成,每个线程都有自己的执行路径和执行状态,可以独立执行指令序列。 线程的出现主要是为了充分利用计算机的多处理器的并行性,提高程序的运行效率。相比于传统的串行执行方式,线程可以同时执行多个任务,大大提高了程序的响应速度和吞吐量。 ## 1.2 Java中的线程概述 Java中的线程是基于操作系统的线程机制实现的,它提供了一种方便的方式来创建和管理线程。Java线程的特性包括以下几点: - **轻量级**:线程是轻量级的执行单元,创建和销毁线程的开销很小。 - **并发执行**:Java程序可以同时执行多个线程,每个线程相互独立,可以并发执行不同的任务。 - **共享内存**:多个线程可以共享相同的内存空间,方便数据的共享与通信。 - **可见性与原子性**:Java提供了各种同步机制来确保多个线程对共享的数据进行安全访问,避免出现数据竞争和并发错误。 在Java中,可以通过继承Thread类、实现Runnable接口以及使用Callable和Future接口来创建线程。接下来,我们将分别介绍这些创建线程的方式。 # 2. 线程的创建 在Java中,线程的创建有多种方式。本章节将介绍三种常见的线程创建方式:继承Thread类、实现Runnable接口以及使用Callable和Future接口。 ### 2.1 继承Thread类 通过继承Thread类来创建线程是最简单的方式之一。我们只需要编写一个类,继承Thread类,并重写其run方法即可。 ```java public class MyThread extends Thread { @Override public void run() { // 线程的执行逻辑写在这里 } } ``` 使用继承Thread类创建线程的示例代码如下: ```java public class ThreadExample { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 启动线程 } } ``` 通过调用`start()`方法来启动线程。`start()`方法会在新线程中执行`run()`方法的内容。 ### 2.2 实现Runnable接口 除了继承Thread类,还可以通过实现Runnable接口来创建线程。实现Runnable接口的好处是可以避免Java单继承的限制,并且更符合面向对象的设计原则。 ```java public class MyRunnable implements Runnable { @Override public void run() { // 线程的执行逻辑写在这里 } } ``` 使用实现Runnable接口创建线程的示例代码如下: ```java public class RunnableExample { public static void main(String[] args) { MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); // 启动线程 } } ``` 在这种方式下,我们需要创建一个Thread对象,并将实现了Runnable接口的对象传入Thread的构造方法中,然后调用`start()`方法来启动线程。 ### 2.3 Callable和Future接口 Callable和Future接口是在Java 5中引入的,用于表示一个可以返回结果的线程任务。与Runnable接口不同,Callable接口中的`call()`方法可以返回一个结果,并且可以抛出异常。 ```java import java.util.concurrent.Callable; public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { // 线程的执行逻辑写在这里 return 42; // 返回一个结果 } } ``` 使用Callable和Future接口创建线程的示例代码如下: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class CallableExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(new MyCallable()); try { int result = future.get(); // 获取线程执行结果 System.out.println("线程执行结果:" + result); } catch (Exception e) { e.printStackTrace(); } executor.shutdown(); // 关闭线程池 } } ``` 在上述示例中,我们通过`Executors.newSingleThreadExecutor()`创建了一个单线程的线程池。然后,通过`submit()`方法提交一个Callable对象,并得到一个Future对象。通过Future对象的`get()`方法可以获取线程执行的结果。最后,关闭线程池。 以上就是线程的创建方式的介绍,我们可以根据具体的需求选择适合的方式来创建线程。 # 3. 线程的启动 在Java中,线程的启动是通过调用`start()`方法来实现的。这一章节将介绍如何启动线程以及线程的生命周期和调度。 ### 3.1 调用start()方法启动线程 使用Java中的线程,最常见的方式是创建一个继承自Thread类的子类,并重写`run()`方法。然后通过调用`start()`方法来启动线程。 下面是一个简单的示例代码: ```java public class MyThread extends Thread { @Override public void run() { // 线程要执行的代码 for (int i = 0; i < 5; i++) { System.out.println("Thread: " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } } ``` 在上面的代码中,我们创建了一个继承自Thread类的子类MyThread,并重写了`run()`方法来定义线程要执行的代码。在`main()`方法中,我们创建一个MyThread对象,并通过调用`start()`方法来启动线程。 值得注意的是,**不能直接调用`run()`方法来启动线程**。直接调用`run()`方法将会在当前线程中执行,而不会创建新的线程。 ### 3.2 线程的生命周期 Java线程的生命周期包含以下状态: - 新建状态(New): 线程对象已经创建,但还没有调用`start()`方法。 - 运行状态(Runnable): 该状态下的线程正在执行`run()`方法中的代码。 - 阻塞状态(Blocked): 线程因为某个原因被暂停执行,例如等待I/O操作完成或获取同步锁。 - 等待状态(Waiting): 线程因为某个条件而等待,直到其他线程改变了该条件。 - 超时等待状态(Timed Waiting): 线程在等待一段时间后会自动恢复到运行状态。 - 终止状态(Terminated): 线程执行完`run()`方法后终止。 Java线程的生命周期如下图所示: ``` +--------+ start() | | +---------->| New | | | | | +---+----+ | | | | | v | +--------+ | | | +----------->|Runnable| run() | | +----------->+--------+ | | | | | v | +--------+ | wait() | | +----------->|Waiting | | | | | +---+----+ | | | | | v | +--------+ | sleep() | | +----------->|Timed | | |Waiting | | +--------+ | | | | | v | +--------+ | | | +----------->| Blocked| I/O | | operation +--------+ ^ | | v +--------+ | | |Terminated| | | +--------+ ``` ### 3.3 线程调度与优先级 Java中的线程调度器负责根据优先级和调度算法决定哪个线程将获得CPU时间,线程的优先级范围从1到10,默认为5。 可以使用`setPriority()`方法设置线程的优先级,例如: ```java Thread myThread = new MyThread(); myThread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级 ``` 然而,**请不要依赖线程的优先级来设计程序的正确行为**,因为线程调度器的行为在不同的操作系统和Java虚拟机下可能会有所不同。因此,尽量避免使用线程的优先级。 在下一章节中,我们将介绍线程同步与通信的方法。 # 4. 线程同步与通信 在多线程编程中,线程同步和线程通信是非常重要的概念。在本章节中,我们将详细介绍如何在Java中实现线程同步与通信的各种方法和技术。 #### 4.1 使用synchronized关键字实现同步 在Java中,可以使用`synchronized`关键字来实现线程同步。通过对关键代码块或方法加锁,可以确保同时只有一个线程执行该代码块或方法。这有助于避免多个线程同时访问共享资源而引发的数据不一致或竞态条件的问题。以下是一个使用`synchronized`关键字的示例: ```java public class SynchronizedExample { private int count = 0; // 同步方法 public synchronized void increment() { count++; } public static void main(String[] args) { SynchronizedExample example = new SynchronizedExample(); for (int i = 0; i < 5; i++) { new Thread(() -> { for (int j = 0; j < 1000; j++) { example.increment(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Count: " + example.count); // 5000 } } ``` 上述示例中,通过将`increment()`方法标记为`synchronized`,确保了多个线程调用该方法时的同步执行,从而避免了并发修改`count`变量的问题。 #### 4.2 使用Lock和Condition进行线程通信 除了`synchronized`关键字,Java中还提供了`Lock`和`Condition`接口来实现线程之间的通信。`Lock`接口提供了比`synchronized`更灵活的锁定方式,而`Condition`接口可以更好地支持等待/通知模式的线程通信。以下是一个使用`Lock`和`Condition`的示例: ```java import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockConditionExample { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean flag = false; public void await() { lock.lock(); try { while (!flag) { condition.await(); } System.out.println("Received the signal"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signal() { lock.lock(); try { flag = true; condition.signalAll(); } finally { lock.unlock(); } } public static void main(String[] args) { LockConditionExample example = new LockConditionExample(); new Thread(() -> { example.await(); }).start(); new Thread(() -> { example.signal(); }).start(); } } ``` 在上述示例中,一个线程调用`await()`方法等待另一个线程发出信号,而另一个线程调用`signal()`方法发送信号,从而唤醒等待的线程。 #### 4.3 线程间的协作与互斥 通过`synchronized`、`Lock`和`Condition`等机制,可以实现线程间的协作和互斥。线程同步和通信是多线程编程中至关重要的一部分,合理地使用这些机制可以避免多线程环境下的数据竞争和错误,保证程序的正确性和稳定性。 以上就是使用`synchronized`关键字和`Lock`、`Condition`接口进行线程同步与通信的介绍。在实际开发中,针对不同的场景和需求,可以灵活选择合适的同步和通信机制来确保多线程程序的正确性和性能。 # 5. 线程池 Java中的线程池是一种重用线程的机制,它可以管理大量的线程并提供线程的生命周期管理、调度、监控等功能。使用线程池可以避免反复创建和销毁线程的开销,提高系统的性能和稳定性。 #### 5.1 Java中的线程池概述 线程池可以通过java.util.concurrent包中的Executor框架来创建和管理。它包括了一系列的线程池实现类,如ThreadPoolExecutor、ScheduledThreadPoolExecutor等。通过线程池,可以实现任务的异步执行、定时任务的调度以及任务的批量处理。 #### 5.2 ThreadPoolExecutor的使用 ThreadPoolExecutor是Java中线程池的一个核心实现类,它提供了丰富的构造函数和自定义配置选项,能够灵活地满足不同场景下的需求。通过ThreadPoolExecutor,可以控制线程池的大小、队列容量、拒绝策略等参数,以及监控线程池的运行状态和执行结果。 ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个固定大小的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); // 提交任务给线程池 for (int i = 0; i < 10; i++) { threadPool.execute(new Task(i)); } // 关闭线程池 threadPool.shutdown(); } static class Task implements Runnable { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName()); } } } ``` ##### 代码总结 - 通过Executors工厂类创建一个固定大小的线程池。 - 提交多个任务给线程池执行,由线程池管理线程的执行过程。 - 在任务的run方法中打印任务执行情况。 ##### 结果说明 该示例代码创建了一个固定大小为5的线程池,提交了10个任务给线程池执行。通过线程池的管理,这10个任务会被分配给5个线程依次执行,最大程度地利用了系统资源。 #### 5.3 Executors工厂类的使用 除了直接使用ThreadPoolExecutor来创建线程池,还可以通过Executors工厂类来快速创建常见类型的线程池,如单线程的线程池、可缓存的线程池、定时任务线程池等。这些线程池的创建和配置都由工厂类封装,简化了线程池的管理和使用。 以上就是线程池的基本概述和使用方法,在实际开发中,合理地使用线程池可以有效地提高系统的性能和并发能力,同时也需要注意线程池的配置和监控,以防止因线程池使用不当而导致的性能问题和系统故障。 # 6. 线程的异常处理 在多线程编程中,线程的异常处理非常重要,合适的异常处理策略可以保证程序的稳定性和可靠性。本章将介绍线程的异常处理方式,并介绍如何使用`UncaughtExceptionHandler`接口来处理线程的未捕获异常。 ### 6.1 线程的异常处理方式 在Java中,线程的异常可以通过以下几种方式来处理: - 在`run()`方法中使用`try-catch`语句捕获异常。 - 在`run()`方法中将异常通过`throws`关键字声明并抛出。 - 使用`Thread.setDefaultUncaughtExceptionHandler()`方法设置默认的未捕获异常处理器。 下面的示例展示了如何使用这些方式来处理线程的异常: ```java public class ThreadExceptionExample extends Thread { @Override public void run() { try { // do something } catch (Exception e) { // 处理异常 } } } public class ThreadExceptionExample2 implements Runnable { @Override public void run() { try { // do something } catch (Exception e) { // 处理异常 } } } public class ThreadExceptionExample3 implements Runnable { @Override public void run() { throw new RuntimeException("线程异常"); } } public class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { // 处理未捕获的异常 } } public class ThreadExceptionHandlingDemo { public static void main(String[] args) { Thread thread1 = new Thread(new ThreadExceptionExample()); Thread thread2 = new Thread(new ThreadExceptionExample2()); thread2.setUncaughtExceptionHandler(new CustomUncaughtExceptionHandler()); Thread thread3 = new Thread(new ThreadExceptionExample3()); Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler()); thread1.start(); thread2.start(); thread3.start(); } } ``` ### 6.2 UncaughtExceptionHandler接口的应用 `Thread.UncaughtExceptionHandler`是一个接口,可以用于处理线程中的未捕获异常。通过实现该接口,可以自定义处理未捕获异常的逻辑。实现该接口需要重写`uncaughtException()`方法,该方法会在线程发生未捕获异常时被调用。在`uncaughtException()`方法中,可以根据需要对异常进行处理、记录日志或进行其他操作。 下面的示例展示了如何使用`UncaughtExceptionHandler`处理线程的未捕获异常: ```java public class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("线程 " + t.getName() + " 发生了未捕获的异常:" + e.getMessage()); // 记录日志、发送报警等其他操作 } } public class ThreadExceptionHandlingDemo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { throw new RuntimeException("线程异常"); } }); thread.setUncaughtExceptionHandler(new CustomUncaughtExceptionHandler()); thread.start(); } } ``` 在上述示例中,我们自定义了一个实现了`Thread.UncaughtExceptionHandler`接口的类`CustomUncaughtExceptionHandler`,并在`run()`方法中抛出了一个运行时异常。在`main()`方法中,我们创建了一个线程并设置了自定义的异常处理器。当线程发生未捕获异常时,异常处理器会被调用,并输出异常信息。 ### 6.3 线程的异常汇总和处理策略 在多线程编程中,需要注意以下几点关于线程异常的处理策略: - 在run()方法中捕获异常需要谨慎处理,应该根据实际情况进行处理,比如重试、回滚等。 - 在使用线程池时,应该及时处理线程的异常,以免影响其他线程的执行。 - 可以通过`UncaughtExceptionHandler`接口来处理未捕获异常,保证程序的稳定性。 - 合理记录和处理线程的异常日志,方便程序的排查和问题的定位。 使用适当的异常处理策略可以提高程序的健壮性和可维护性,避免因为异常而导致程序崩溃或不可预期的结果发生。 本章介绍了线程的异常处理方式,并展示了如何使用`UncaughtExceptionHandler`接口处理线程的未捕获异常。通过合理处理线程的异常,可以提高程序的可靠性和稳定性,同时也更便于排查和定位问题。在实际编程中,需要根据具体的业务需求和场景选择合适的异常处理策略。
corwn 最低0.47元/天 解锁专栏
赠618次下载
profit 百万级 高质量VIP文章无限畅学
profit 千万级 优质资源任意下载
profit C知道 免费提问 ( 生成式Al产品 )

相关推荐

SW_孙维

开发技术专家
知名科技公司工程师,开发技术领域拥有丰富的工作经验和专业知识。曾负责设计和开发多个复杂的软件系统,涉及到大规模数据处理、分布式系统和高性能计算等方面。
专栏简介
本专栏将深入探讨Java编程中的多线程编程与并发控制,旨在帮助读者全面理解和掌握Java多线程相关的知识和技能。首先从Java多线程基础概念与原理入手,逐步介绍Java中线程的创建与启动、多线程的同步与互斥、线程的通信与协作以及线程池的原理与使用。随后重点讲解线程的状态与生命周期管理、锁的分类与应用场景、并发集合与线程安全容器、以及可重入锁、非公平锁、读写锁等具体知识。此外,还将深入探讨线程死锁与解救策略、线程停止与中断机制、线程调度与优先级控制、线程组与异常处理、守护线程与用户线程、线程局部变量与全局变量、以及线程性能调优与分析等方面,最后还将重点讲解线程池参数调优与监控。通过本专栏的学习,读者将掌握Java多线程编程的精髓,为应对各种并发场景和实际应用提供坚实的理论基础和实用技能。
最低0.47元/天 解锁专栏
赠618次下载
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
C知道 免费提问 ( 生成式Al产品 )

最新推荐

Python字符串操作:strip()函数的最佳实践指南,提升字符串处理技能

![Python字符串操作:strip()函数的最佳实践指南,提升字符串处理技能](https://pic3.zhimg.com/80/v2-ff7219d40ebe052eb6b94acf9c74d9d6_1440w.webp) # 1. Python字符串操作基础 Python字符串操作是处理文本数据的核心技能。字符串操作基础包括: - **字符串拼接:**使用`+`运算符连接两个字符串。 - **字符串切片:**使用`[]`运算符获取字符串的子字符串。 - **字符串格式化:**使用`f`字符串或`format()`方法将变量插入字符串。 - **字符串比较:**使用`==`和`!=

Python Requests库与云计算合作:在云环境中部署和管理HTTP请求,轻松自如

![Python Requests库与云计算合作:在云环境中部署和管理HTTP请求,轻松自如](http://www.yunchengxc.com/wp-content/uploads/2021/02/2021022301292852-1024x586.png) # 1. Python Requests库简介** Requests库是一个功能强大的Python HTTP库,用于发送HTTP请求并获取响应。它简化了HTTP请求的处理,提供了高级功能,例如会话管理、身份验证和异常处理。Requests库广泛用于云计算、Web抓取和API集成等各种应用程序中。 Requests库提供了直观且易于

PyCharm Python代码审查:提升代码质量,打造健壮的代码库

![PyCharm Python代码审查:提升代码质量,打造健壮的代码库](https://ask.qcloudimg.com/http-save/8983410/08337732e430daf83da4bd4acffc043a.png) # 1. PyCharm Python代码审查概述 PyCharm 是一款功能强大的 Python IDE,它提供了全面的代码审查工具和功能,帮助开发人员提高代码质量并促进团队协作。代码审查是软件开发过程中至关重要的一步,它涉及对代码进行系统地检查,以识别错误、改进代码结构并确保代码符合最佳实践。PyCharm 的代码审查功能使开发人员能够有效地执行此过程

Python数据可视化:使用Matplotlib和Seaborn绘制图表和可视化数据的秘诀

![Python数据可视化:使用Matplotlib和Seaborn绘制图表和可视化数据的秘诀](https://img-blog.csdnimg.cn/img_convert/fa4ff68408814a76451f2a4cc4328954.png) # 1. Python数据可视化的概述 Python数据可视化是一种利用Python编程语言将数据转化为图形表示的技术。它使数据分析师和科学家能够探索、理解和传达复杂数据集中的模式和趋势。 数据可视化在各个行业中都有广泛的应用,包括金融、医疗保健、零售和制造业。通过使用交互式图表和图形,数据可视化可以帮助利益相关者快速识别异常值、发现趋势并

Python读取MySQL数据金融科技应用:驱动金融创新

![Python读取MySQL数据金融科技应用:驱动金融创新](https://image.woshipm.com/wp-files/2020/06/8ui3czOJe7vu8NVL23IL.jpeg) # 1. Python与MySQL数据库** Python是一种广泛用于数据分析和处理的编程语言。它与MySQL数据库的集成提供了强大的工具,可以高效地存储、管理和操作数据。 **Python连接MySQL数据库** 要连接Python和MySQL数据库,可以使用PyMySQL模块。该模块提供了一个易于使用的接口,允许Python程序与MySQL服务器进行交互。连接参数包括主机、用户名、

Assert在人工智能和机器学习中的应用:提升模型准确性,增强可解释性

![Assert在人工智能和机器学习中的应用:提升模型准确性,增强可解释性](https://appserversrc.8btc.cn/FpJXlkyuZESaSwJ7gDzgBfAwFjnR) # 1. Assert在人工智能和机器学习中的概述 **1.1 Assert的概念** Assert是一种程序断言,它允许开发者在代码中指定条件,如果条件不满足,则触发错误或警告。在人工智能和机器学习中,Assert可用于验证数据质量、模型逻辑和预测结果。 **1.2 Assert的优势** 使用Assert具有以下优势: - **提高代码可靠性:**通过验证关键条件,Assert有助于防止

Macbook上Python科学计算:使用NumPy和SciPy进行数值计算,让科学计算更轻松

![Macbook上Python科学计算:使用NumPy和SciPy进行数值计算,让科学计算更轻松](https://ask.qcloudimg.com/http-save/8934644/fd9a445a07f11c8608626cd74fa59be1.png) # 1. Python科学计算简介 Python科学计算是指使用Python语言和相关库进行科学和工程计算。它提供了强大的工具,可以高效地处理和分析数值数据。 Python科学计算的主要优势之一是其易用性。Python是一种高级语言,具有清晰的语法和丰富的库生态系统,这使得开发科学计算程序变得容易。 此外,Python科学计算

Python中sorted()函数的代码示例:实战应用,巩固理解

![Python中sorted()函数的代码示例:实战应用,巩固理解](https://ucc.alicdn.com/pic/developer-ecology/kisy6j5ipul3c_67f431cd24f14522a2ed3bf72ca07f85.jpeg?x-oss-process=image/resize,s_500,m_lfit) # 1. Python中sorted()函数的基本用法 sorted()函数是Python中用于对可迭代对象(如列表、元组、字典等)进行排序的内置函数。其基本语法如下: ```python sorted(iterable, key=None, re

Python调用Shell命令的常见面试题:深度解析,轻松应对

![Python调用Shell命令的常见面试题:深度解析,轻松应对](https://img-blog.csdnimg.cn/2021083009010299.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASElNX01SWQ==,size_20,color_FFFFFF,t_70,g_se,x_16) # 1. Python调用Shell命令的基础 Python提供了多种方式来调用Shell命令,这为自动化任务和与系统交互提供了强大的功能。本章将介绍Python调用

Python数据写入Excel:行业案例研究和应用场景,了解实际应用

![Python数据写入Excel:行业案例研究和应用场景,了解实际应用](https://img-blog.csdnimg.cn/img_convert/6aecf74ef97bbbcb5bc829ff334bf8f7.png) # 1. Python数据写入Excel的理论基础 Python数据写入Excel是将数据从Python程序传输到Microsoft Excel工作簿的过程。它涉及到将数据结构(如列表、字典或数据框)转换为Excel中表格或工作表的格式。 数据写入Excel的理论基础包括: - **数据格式转换:**Python中的数据结构需要转换为Excel支持的格式,如文