Java 多线程(2)-线程创建
最编程
2024-10-08 07:08:07
...
Java多线程(2)—线程创建
一、线程创建简介
在Java中,创建线程可以通过两种主要方式:继承 Thread
类、实现 Runnable
、实现Callable 接口和线程池。
二、创建方式
2.1 继承 Thread 类
示例1
♠①:创建一个类继承 Thread 类,并重写 run 方法。
package com.example.demo10.ccc;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 200; i++){
System.out.println(getName() + ":打了" +i+ "个小兵");
}
}
}
package com.example.demo10.ccc;
public class MyThreadDemo {
public static void main(String[] args) {
//创建两个线程对象
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
//设置线程名字
myThread1.setName("张飞");
myThread2.setName("赵子龙");
myThread1.start();
myThread2.start();
}
}
备注:这里如果使用run方法,是顺序执行
2.2 实现 Runnable 接口
♠②:创建一个类实现 Runnable 接口,并重写 run 方法。
一般使用实现Runnable接口
- 可以避免java中的单继承的限制
- 应该将并发运行任务和运行机制解耦,因此我们选择实现Runnable接口这种方式!
示例1
package com.example.demo10.ccc;
public class MyRunnableDemo {
public static void main(String[] args) {
//创建MyRunnable类
MyRunnable myRunnable = new MyRunnable();
//创建Thread类的有参构造,并设置线程名
Thread t1 = new Thread(myRunnable, "关羽");
Thread t2 = new Thread(myRunnable, "吕布");
//启动线程
t1.start();
t2.start();
}
}
package com.example.demo10.ccc;
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 300; i++){
System.out.println(Thread.currentThread().getName() + ":打了" + i+ "个兵");
}
}
}
2.3 实现 Callable 接口
♠③:实现 Callable 接口,重写 call 方法,这种方式可以通过 FutureTask 获取任务执行的返回值。
示例
package com.example.demo10.ccc.callable;
import java.util.concurrent.*;
public class SimpleTask implements Callable<String> {
private String taskName;
public SimpleTask(String name) {
this.taskName = name;
}
@Override
public String call() throws Exception {
return "Task " + taskName + ":执行完成";
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
Future<String> future1 = executor.submit(new SimpleTask("A"));
Future<String> future2 = executor.submit(new SimpleTask("B"));
Future<String> future3 = executor.submit(new SimpleTask("C"));
System.out.println(future1.get());
System.out.println(future2.get());
System.out.println(future3.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
解释:
类 SimpleTask
import java.util.concurrent.Callable;
public class SimpleTask implements Callable<String> {
private String taskName;
public SimpleTask(String taskName) {
this.taskName = taskName;
}
@Override
public String call() throws Exception {
return "Task " + taskName + " completed";
}
}
-
SimpleTask
类实现了Callable<String>
接口,这意味着它的call()
方法返回一个String
类型的结果。 - 构造函数
SimpleTask(String taskName)
接收一个任务名,将其存储在taskName
成员变量中。
主程序 main 方法
import java.util.concurrent.*;
public class SimpleTask implements Callable<String> {
// SimpleTask 类的定义在这里,上面已经展示过了
public static void main(String[] args) {
// 创建一个固定大小为3的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
// 提交任务A,返回一个Future对象
Future<String> future1 = executor.submit(new SimpleTask("A"));
// 提交任务B,返回一个Future对象
Future<String> future2 = executor.submit(new SimpleTask("B"));
// 提交任务C,返回一个Future对象
Future<String> future3 = executor.submit(new SimpleTask("C"));
// 获取并打印任务A的结果
System.out.println(future1.get());
// 获取并打印任务B的结果
System.out.println(future2.get());
// 获取并打印任务C的结果
System.out.println(future3.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
// 关闭线程池
executor.shutdown();
}
}
}
主程序执行流程说明:
-
创建线程池: 使用
Executors.newFixedThreadPool(3)
创建一个固定大小为3的线程池executor
。 -
提交任务:
- 通过
executor.submit(new SimpleTask("A"))
提交任务A,返回一个Future<String>
对象future1
。 - 通过
executor.submit(new SimpleTask("B"))
提交任务B,返回一个Future<String>
对象future2
。 - 通过
executor.submit(new SimpleTask("C"))
提交任务C,返回一个Future<String>
对象future3
。
- 通过
-
获取结果:
- 使用
future1.get()
获取并打印任务A的结果。 - 使用
future2.get()
获取并打印任务B的结果。 - 使用
future3.get()
获取并打印任务C的结果。
- 使用
-
异常处理与关闭线程池:
- 使用
try-catch
块捕获可能抛出的InterruptedException
和ExecutionException
异常。 - 在
finally
块中调用executor.shutdown()
关闭线程池,确保资源被正确释放。
- 使用
总结
这段代码展示了如何利用线程池和 Callable
接口实现并发任务的提交和执行,并且展示了如何通过 Future
对象获取每个任务的执行结果。这种方式能够有效地管理多个并发任务,提高程序的执行效率和性能。
2.4 使用线程池
在实际应用中,频繁地创建和销毁线程会带来性能开销,因此使用线程池是更为高效的选择。Java提供了 Executor
框架来管理线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
}
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池
for (int i = 0; i < 10; i++) {
executorService.submit(new MyRunnable()); // 提交任务
}
executorService.shutdown(); // 关闭线程池
}
}
上一篇: 奇异值分解 SVD - 什么是奇异值?
下一篇: 9 微服务最佳实践