jayqia 发表于 2023-7-5 22:43

java多线程知识实例代码及结果描述


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()方法在运行");
      }
    }
}
```

结果:

!(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);

qiaodan81 发表于 2023-7-5 23:10

现在线程使用 以及线程等待基本都用框架了,

shksky 发表于 2023-7-5 23:36

多谢分享!!辛苦晒!!

wzw001 发表于 2023-7-6 00:14


蛮实用的,多谢分享!

eagle1996 发表于 2023-7-6 00:39

qiaodan81 发表于 2023-7-5 23:10
现在线程使用 以及线程等待基本都用框架了,

框架是啥意思m

afo2023 发表于 2023-7-6 03:20

有问题的,以后还望大佬多指教

jayqia 发表于 2023-7-6 07:45

qiaodan81 发表于 2023-7-5 23:10
现在线程使用 以及线程等待基本都用框架了,

哈哈,这个是学校课程里面的内容,确实现在的开发都是在框架基础上进行修补

bean0283 发表于 2023-7-6 09:09

eagle1996 发表于 2023-7-6 00:39
框架是啥意思m

常用的是spring,spring mvc,spring boot,提高开发效率

ruanjl 发表于 2023-7-6 09:32

谢谢分享
页: [1]
查看完整版本: java多线程知识实例代码及结果描述