2.多线程好处

不管多线程的挑战仍然被使用的原因,是因为多线程仍然有几个益处,这些益处中的一些是:

  • 更好的资源利用
  • 在一些场景下简单的程序设计
  • 更快响应的程序
更好的资源利用
想象一个应用读取和处理来自于本地文件系统的文件。让我们说从磁盘中读取一个文件花费5秒钟,处理它花费2秒钟,执行两个文件将会花费:
  5 seconds reading file A
  2 seconds processing file A
  5 seconds reading file B
  2 seconds processing file B
-----------------------
 14 seconds total

当从磁盘中读文件的时候,大部分的CPU时间都花费在等待文件读取上了。在那个时间CPU是相当空闲的。它可以做一些其他的事情。通过改变这个操作的顺序,CPU可以被更好的利用。看看这个顺序:
  5 seconds reading file A
  5 seconds reading file B + 2 seconds processing file A
  2 seconds processing file B
-----------------------
 12 seconds total

CPU等待第一个文件被读。然后它开始读取第二个文件。当第二个文件正在被读取的时候,这个CPU执行第一个文件。记住,当等待文件从磁盘中读取的时候,这个CPU大部分时间是空闲的。
通常情况下,CPU在等待IO的时候可以做一些其他的事情。它不一定必须是磁盘IO。它也可能是网络IO,或者是来自一个用户的输入。网络和磁盘IO比CPU的和内存IO慢很多。
更简单的程序设计
如果你正在单线程应用中手工的编写上面的读取和处理文件的顺序的程序,你将不得不跟踪每一个文件的读取和处理的状态。代替的,你可以启动两个线程,每一个线程都只是读取和处理一个单独的文件。这些线程中的每一个当等待磁盘读取文件的时候都会被堵塞。当等待的时候,其他的线程可以使用CPU去处理他们已经读到的文件的部分。这个结果就是磁盘将会一致保持忙碌状态,读取各种各样的文件进入内存。这个结果就是更好的利用了磁盘和CPU。它也会更简单的去编写程序,因为一个线程只是跟踪一个单独的文件。
更快响应的程序
另外一个公共的目标就是将一个单线程的应用转换成多线程的应用将会获得一个更快响应的应用。想象一个服务器应用,它正在监听进来请求的一些端口。当一个请求接收到了之后,他处理这个请求,然后再返回去监听。这个服务器循环概述如下:
 while(server is active){
    listen for request
    process request
  }

如果这个请求花费很长时间去处理,在那段时间中没有新的客户端发送请求到服务器。只有服务器可以监听接收的请求。
一个替换的设计就是对于监听的线程把一个请求传给一个worker线程,并且立刻返回监听。这个worker线程将会执行这个请求以及发送一个应答到客户端,这个设计概述如下
while(server is active){
    listen for request
    hand request to worker thread
  }

这个方式,服务器线程将会很快返回到监听器。因此更多的客户端可以发送请求到服务器。这服务器变得更快的响应了。
对于桌面应用同样也是一样的。如果你点击一个按钮开启一个长时间的任务,并且正在执行任务的线程是这个正在更新窗口,按钮等等的线程,然后当任务执行的时候,这个应用出现不响应的情况。代替的,这个任务可以转换成一个worker线程。当worker线程忙着处理任务的时候,这个窗口线程可以空闲的去响应其他用户的请求。当worker线程完成的时候,它会发出信号通知窗口线程。这个窗口线程然后可以根据这个任务的结果更新应用窗口。使用worker线程设计的程序将会给予用户更快的响应。

翻译地址:http://tutorials.jenkov.com/java-concurrency/benefits.html

<think>好的,我需要帮助用户找到关于Java多线程编程的示例代码。根据用户的问题,他们希望看到具体的代码示例,并且可能对多线程的基础知识和实现方式感兴趣。首先,我应该回顾用户提供的引用内容,看看有哪些相关的代码示例可以引用。 引用[3]提到了通过继承Thread类并重写run()方法来创建线程,并提供了示例代码。这是一个基础且常见的方法,适合作为第一个示例。接着,引用[4]展示了使用Runnable接口和生产者-消费者模型的代码,这可以展示不同的线程实现方式以及线程间的协作,特别是涉及到线程同步的部分,比如使用队列和sleep方法控制生产消费速度。此外,用户可能还想了解线程池的使用,虽然引用中没有直接提到,但线程池是Java多线程中的一个重要部分,所以应该补充一个相关的示例,比如使用ExecutorService。 接下来,我需要确保代码格式正确,符合用户要求的行内数学表达式和独立公式的格式,但在这个问题中主要是代码示例,所以可能不需要数学表达式。不过要检查LaTeX语法是否正确,但用户的问题主要关于代码,所以重点放在代码结构上。 另外,用户要求生成相关问题,我需要根据提供的示例内容提出相关的问题,比如不同实现方式的区别、线程同步的方法、线程池的好处等。 在回答结构上,需要分步骤说明不同的多线程实现方法,每个方法配以代码示例,并解释关键点。最后列出相关问题,帮助用户进一步学习。 现在需要确认所有引用的内容是否正确使用,比如引用[3]和[4]中的代码是否准确,以及是否覆盖了用户的需求。用户可能还需要知道如何启动线程、如何处理线程间通信,以及如何避免常见的多线程问题,如竞态条件,但根据现有引用,可能没有涉及同步锁(synchronized)或显式锁(ReentrantLock)的示例,但引用[4]中的队列可能隐含使用了线程安全的队列,比如BlockingQueue,所以需要指出这一点。 总结回答结构: 1. 继承Thread类的方法(引用[3]) 2. 实现Runnable接口(补充示例,可能结合引用[4]) 3. 生产者-消费者模型(引用[4]) 4. 使用线程池(补充内容) 每个部分给出代码示例并解释关键点,最后生成相关问题。</think>### Java多线程编程代码示例 #### 1. 继承Thread类实现线程 通过继承`Thread`类并重写`run()`方法创建线程[^3]: ```java public class MyThread extends Thread { public void run() { System.out.println("线程ID:" + Thread.currentThread().getId()); } public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.start(); // 启动线程1 t2.start(); // 启动线程2 } } ``` **关键点**:直接调用`start()`方法启动线程,JVM会自动调用`run()`方法。 --- #### 2. 实现Runnable接口 通过实现`Runnable`接口避免单继承限制[^2]: ```java public class MyRunnable implements Runnable { public void run() { System.out.println("线程名称:" + Thread.currentThread().getName()); } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable()); Thread t2 = new Thread(new MyRunnable()); t1.start(); t2.start(); } } ``` **优势**:更灵活,适合资源共享场景。 --- #### 3. 生产者-消费者模型(线程协作) 使用`BlockingQueue`实现线程间通信[^4]: ```java import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class ProducerConsumerDemo { static BlockingQueue<String> queue = new ArrayBlockingQueue<>(5); public static void main(String[] args) { // 生产者线程(每500ms生产一个元素) Thread producer = new Thread(() -> { int n = 1; while (true) { try { queue.put("元素" + n); System.out.println("生产: 元素" + n); n++; Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 消费者线程(每2秒消费一个元素) Thread consumer = new Thread(() -> { while (true) { try { String item = queue.take(); System.out.println("消费: " + item); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); producer.start(); consumer.start(); } } ``` **关键机制**:`BlockingQueue`自动处理线程阻塞与唤醒,保证队列线程安全。 --- #### 4. 使用线程池(ExecutorService) 通过线程池管理线程资源: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(3); for (int i = 1; i <= 5; i++) { pool.execute(() -> { System.out.println("任务由线程" + Thread.currentThread().getName() + "执行"); }); } pool.shutdown(); } } ``` **优势**:降低资源消耗,提高线程复用率。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值