Java多线程(2)—线程创建
一、线程创建简介
在Java中,创建线程可以通过两种主要方式:继承 Thread
类、实现 Runnable
、实现Callable 接口和线程池。
二、创建方式
2.1 继承 Thread 类
示例1
♠①:创建一个类继承 Thread 类,并重写 run 方法。
package com.example.demo10.ccc;public class MyThread extends Thread{@Overridepublic 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{@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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(); // 关闭线程池}
}