好友
阅读权限10
听众
最后登录1970-1-1
|
[md]Java提供了3种多线程的创建方式:
(1)继承javal.ang包中的Thread类,重写 Thread类的run()方法,在run()方法中实现多线程代码。
(2)实现javal.ang.Runnable接口,在run()方法中实现多线程代码。
(3)实现java.util.concurrent.Callable接口,重写call()方法,并使用 Future接口获取call()方法返回的结果。
案例1:运行下面的程序,分析输出结果
```java
package cn.edu.ahut.p13;
public class Example01 {
public static void main(String[] args) {
MyThread01 myThread = new MyThread01(); // 创建MyThread01实例对象
myThread.run(); // 调用MyThread01类的run()方法
while (true) { // 该循环是一个死循环,打印输出语句
System.out.println("Main方法在运行");
}
}
}
class MyThread01 {
public void run() {
while (true) { // 该循环是一个死循环,打印输出语句
System.out.println("MyThread类的run()方法在运行");
}
}
}
```
运行截图;
![](C:\Users\jay-qiao\AppData\Roaming\Typora\typora-user-images\image-20230509180914044.png)
根据代码分析,结果会是无限循环地打印两行信息:
"MyThread类的run()方法在运行"
"Main方法在运行"
这是因为在`main`方法中,首先创建了一个`MyThread01`的实例对象`myThread`,然后调用了`myThread.run()`方法。但是需要注意的是,`myThread.run()`并不会创建一个新的线程来执行`MyThread01`类中的代码,而是直接在当前的主线程上执行。因此,`MyThread01`类的`run()`方法会一直循环打印信息"MyThread类的run()方法在运行"。
同时,在`main`方法中,存在一个无限循环的`while`循环,不会停止执行。在每次循环中,会打印信息"Main方法在运行"。
因此,程序会无限循环地交替打印这两行信息,直到程序被手动终止。
​ Thread类
为了实现多线程,Java提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。在Thread类中提供了一个start()方法用于启动新线程,新线程启动后,JVM会自动调用run()方法,如果子类重写了run()方法便会执行子类中的run()方法。
案例2:Thread类实现多线程
```java
package cn.edu.ahut.p13;
public class Example02 {
public static void main(String[] args) {
MyThread02 myThread = new MyThread02(); // 创建MyThread02的线程对象
myThread.start(); // 开启线程
while (true) { // 通过死循环语句打印输出
System.out.println("main()方法在运行");
}
}
}
class MyThread02 extends Thread {
public void run() {
while (true) { // 通过死循环语句打印输出
System.out.println("MyThread类的run()方法在运行");
}
}
}
```
运行截图;
![](C:\Users\jay-qiao\AppData\Roaming\Typora\typora-user-images\image-20230509181508403.png)
代码中有两个线程:主线程(main)和自定义线程(MyThread02)。主线程和自定义线程都通过死循环语句打印输出。
当程序运行时,主线程首先创建并启动了自定义线程对象myThread。然后,主线程进入一个无限循环,在循环内部打印输出"main()方法在运行"。同时,自定义线程对象myThread也进入一个无限循环,在循环内部打印输出"MyThread类的run()方法在运行"。
因为两个线程都是无限循环的,所以会一直执行打印输出语句。输出结果将交替出现,没有固定的顺序。可能的输出结果是:
```
main()方法在运行
MyThread类的run()方法在运行
main()方法在运行
MyThread类的run()方法在运行
...
```
由于两个线程都在不断地执行循环体,没有终止条件,所以程序将一直运行下去。这是一个典型的多线程并发执行的例子。
Runnable接口
继承Thread类实现多线程的弊端
​ 因为Java只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,比如学生类Student继承了Person类,那么Student类就无法再通过继承Thread类创建线程
Thread类提供了另外一个构造方法Thread(Runnable target),其中参数类型Runnable是一个接口,它只有一个run()方法。当通过Thread(Runnable target)构造方法创建线程对象时,只需为该方法传递一个实现了Runnable接口的对象,这样创建的线程将实现了Runnable接口中的run()方法作为运行代码,而不需要调用Thread类中的run()方法。
案例3:通过实现Runnable接口的方式来创建多线程
```{java}
package cn.edu.ahut.p13;
class MyThread03 implements Runnable {
public void run() {// 线程的代码段,当调用start()方法时,线程从此处开始执行
while (true) {
System.out.println("MyThread类的run()方法在运行");
}
}
}
public class Example03 {
public static void main(String[] args) {
MyThread03 myThread = new MyThread03(); // 创建MyThread03的实例对象
Thread thread = new Thread(myThread); // 创建线程对象
thread.start(); // 开启线程,执行线程中的run()方法
while (true) {
System.out.println("main()方法在运行");
}
}
}
```
该代码创建了一个实现了Runnable接口的线程类MyThread03,并在其中实现了run()方法。在run()方法中,使用一个无限循环来输出"MyThread类的run()方法在运行"。
在Example03的main()方法中,首先创建了MyThread03的实例对象myThread,然后通过该实例对象创建了一个Thread对象thread。接下来调用thread的start()方法来启动线程,从而执行线程中的run()方法。
在启动线程后,主线程继续执行while循环,输出"main()方法在运行"。由于主线程和MyThread03线程是并行执行的,因此两个循环的输出会交替进行。
然而,由于MyThread03的run()方法中使用了一个无限循环,线程不会自动结束。因此,无论是主线程还是MyThread03线程,都会一直输出相应的内容,程序不会停止。
因此,运行该代码会不断交替输出"main()方法在运行"和"MyThread类的run()方法在运行",并且程序不会停止,需要手动终止程序。
运行结果:
![](C:\Users\jay-qiao\AppData\Roaming\Typora\typora-user-images\image-20230509181942794.png)
实现Callable接口
通过Thread类和Runnable接口实现多线程时,需要重写run()方法,但是由于run()方法没有返回值,因此无法从新线程中获取返回结果。为了解决这个问题,Java提供了一个Callable接口,来满足这种既能创建新线程又可以有返回值的需求。
Callable接口的方式创建线程步骤
​ (1)创建一个Callable接口的实现类,同时重写Callable接口的call()方法。
​ (2)创建Callable接口的实现类对象。
​ (3)通过FutureTask线程结果处理类的有参构造方法封装Callable接口实现类对象。
​ (4)调用参数为FutureTask类对象的Thread有参构造方法创建Thread线程实例。
​ (5)调用线程实例的start()方法启动线程。
示例:通过实现Callable接口的方式来创建多线程
```java
package cn.edu.ahut.p13;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread04 implements Callable<Object> {
// 重写Callable接口的call()方法
public Object call() throws Exception {
int i = 0;
while (i++ < 5) {
System.out.println(Thread.currentThread().getName()
+ "的call()方法在运行");
}
return i;
}
}
public class Example04{
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyThread04 myThread = new MyThread04(); // 创建Callable接口的实例对象
//使用FutureTask封装MyThread04类
FutureTask<Object> ft1 = new FutureTask<>(myThread);
//使用Thread(Runnable target ,String name)构造方法创建线程对象
Thread thread1 = new Thread(ft1, "thread");
//调用线程对象的start()方法启动线程
thread1.start();
//通过FutureTask对象的方法管理返回值
System.out.println(Thread.currentThread().getName()+ "的返回结果:"+ ft1.get());
int a=0;
while (a++<5) {
System.out.println("main()方法在运行");
}
}
}
```
结果:
![image-20230509182619734](C:\Users\jay-qiao\AppData\Roaming\Typora\typora-user-images\image-20230509182619734.png)
分析:
给定的代码会先执行`MyThread04`的`call()`方法,然后才会执行`main()`方法。`call()`方法会打印五次线程名,而`main()`方法会打印五次"main()方法在运行"。由于使用了`FutureTask`,`main()`方法会等待`call()`方法执行完毕并获取其返回结果后才会继续执行
四、线程操作的相关方法
案例5:演示不同优先级的两个线程的运行情况
步骤一:定义MaxPriority类并实现Runnable接口。在MaxPriority中,使用for循环打印正在发售的票数。代码如下所示:
步骤一:定义MaxPriority类并实现Runnable接口。在MaxPriority中,使用for循环打印正在发售的票数。代码如下所示:
```java
class MaxPriority implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "正在输出:" + i);
}
}
}
```
步骤二:定义MinPriority类并实现Runnable接口。在MinPriority中,使用for循环打印正在发售的票数。代码如下所示:
```java
class MinPriority implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "正在输出:" + i);
}
}
}
```
步骤三:定义main()方法,创建两个线程,分别设置线程的优先级,然后开启线程。代码如下所示:
```java
public static void main(String[] args) {
// 创建两个线程
Thread minPriority = new Thread(new MinPriority(), "优先级较低的线程");
Thread maxPriority = new Thread(new MaxPriority(), "优先级较高的线程");
minPriority.setPriority(Thread.MIN_PRIORITY); |
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|