欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Java 多线程(2)-线程创建

最编程 2024-10-08 07:08:07
...

Java多线程(2)—线程创建

一、线程创建简介

在Java中,创建线程可以通过两种主要方式:继承 Thread​ 类、实现 Runnable​ 、实现Callable ​接口和线程池。

748f67c0-e1cb-4d4e-8910-22d4fe729620

二、创建方式

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

image

备注:这里如果使用run方法,是顺序执行

image

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+ "个兵");
        }
    }
}

image

image

2.3 实现 Callable 接口

♠③:实现 Callable 接口,重写 call 方法,这种方式可以通过 FutureTask 获取任务执行的返回值。

示例

image

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

主程序执行流程说明:

  1. 创建线程池: 使用 Executors.newFixedThreadPool(3)​ 创建一个固定大小为3的线程池 executor​。

  2. 提交任务:

    • 通过 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​。
  3. 获取结果:

    • 使用 future1.get()​ 获取并打印任务A的结果。
    • 使用 future2.get()​ 获取并打印任务B的结果。
    • 使用 future3.get()​ 获取并打印任务C的结果。
  4. 异常处理与关闭线程池:

    • 使用 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(); // 关闭线程池
    }
}

image