并发编程之基础知识篇--创建线程的四种方式

目录 

继承Thread类

扩展小知识:

Thread类的常见方法

Thread 类的静态方法

实现Runnable接口

使用Callable和Future创建线程

使用Executor框架创建线程池


继承Thread类

  1. 创建一个继承自Thread类的子类,并重写其run()方法,将相关逻辑实现,run()方法就是线程要执行的业务逻辑方法。
  2. 创建自定义的线程子类对象
  3. 调用子类实例的star()方法来启动线程

为了更好地理解单线程和多线程的执行过程,接下来通过一个图例分析一下单线程和多线程的区别。

从上图可以看出,单线程的程序在运行时,会按照代码的调用顺序执行,而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响,这正是单线程和多线程的区别。

示例代码如下:

class MyThread extends Thread {
    public void run() {
        // 线程执行的代码逻辑
        System.out.println(Thread.currentThread().getName() +"线程正在运行");
    }
}
public class Main {
    public static void main(String[] args) {
        // 创建线程并启动
        MyThread thread = new MyThread();
        thread.start();
        System.out.println(Thread.currentThread().getName() + " main()方法执行结束");
    }
}

运行结果:

main main()方法执行结束
Thread-0线程正在运行

扩展小知识:

Thread类的常见方法

  1. start(): 启动线程,并使其进入可运行状态,当CPU调度到该线程时,会自动调用其run()方法开始执行线程代码。
  2. run(): 线程的执行逻辑,通常需要在子类中重写该方法以定义具体的线程行为。通过调用start()方法来启动线程时,系统会自动调用该方法。
  3. sleep(long millis): 让当前线程暂停执行指定的时间(以毫秒为单位),进入阻塞状态。暂停期间不占用CPU时间,其他线程可以继续执行。
  4. join(): 当一个线程A调用另一个线程B的join()方法时,线程A将会等待线程B执行完毕后才继续执行。
  5. holdsLock(Object x):当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
  6. dumpStack():将当前线程的堆栈跟踪打印至标准错误流。
  7. getName(): 获取线程的名称。
  8. setName(String name): 设置线程的名称。
  9. getId(): 获取线程的唯一标识符。
  10. isAlive(): 判断线程是否存活,即线程是否已启动但尚未终止。
  11. setPriority(int priority): 设置线程的优先级,优先级范围为1-10,默认为5。优先级较高的线程在竞争资源时有更大的概率优先执行。
  12. yield(): 暂停当前正在执行的线程,并让出CPU资源给其他具有相同优先级的线程。仅是一种建议,不保证有效,具体是否产生效果取决于系统的调度器。
  13. interrupt(): 中断线程,给线程发送中断信号。线程在合适的时候可以检查到该中断请求,然后自行决定如何响应。
  14. isInterrupted(): 判断线程是否被中断,返回布尔值。
  15. static boolean interrupted(): 判断当前线程是否被中断,并清除中断状态。

Thread 类的静态方法

currentThread() 是 Thread 类的静态方法,它返回当前正在执行的线程对象。具体来说,它返回一个表示当前线程的 Thread 对象。

可以使用 Thread.currentThread() 来获取当前线程的引用。这个方法常用于需要获得当前执行线程对象的场景,例如需要在运行时获取线程的名称、线程优先级、判断线程是否被中断等操作。

注意:currentThread() 是 Thread 类的静态方法,因此可以直接通过 Thread.currentThread() 的方式调用,不需要创建 Thread 对象实例。

下面是一个示例代码,演示如何使用 currentThread() 方法:

public class Main {
    public static void main(String[] args) {
        // 获取当前线程对象
        Thread currentThread = Thread.currentThread();

        // 获取当前线程的名称
        String threadName = currentThread.getName();
        System.out.println("当前线程名称:" + threadName);//当前线程名称:main

        // 获取当前线程的优先级
        int threadPriority = currentThread.getPriority();
        System.out.println("当前线程优先级:" + threadPriority);//当前线程优先级:5

        // 判断当前线程是否被中断
        boolean isInterrupted = currentThread.interrupted();
        System.out.println("当前线程是否被中断:" + isInterrupted);//当前线程是否被中断:false
    }
}

注意:getPriority() 方法是 Thread 类的实例方法,用于获取线程的优先级。该方法返回一个表示线程优先级的整数值。

线程优先级的范围是从 1 到 10,默认优先级为 5。较大的优先级值意味着线程更重要或更紧急,但并不保证高优先级的线程总是比低优先级的线程先执行。

实现Runnable接口

  1. 创建一个类实现Runnable接口,并重写其run()方法。
  2. 然后创建Thread对象,并将该实现Runnable接口的类的实例作为参数传递给Thread构造函数。
  3. 最后调用Thread对象的start()方法启动线程。

注意,实现 Runnable 接口相比直接继承 Thread 类具有更好的灵活性和可扩展性,因为它允许多个线程共享相同的 Runnable 实例。

下面是一个实现 Runnable 接口的示例代码:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 在此处添加想要线程执行的代码逻辑
        System.out.println("线程运行中");
    }
}
public class Main {
    public static void main(String[] args) {
        // 创建 MyRunnable 实例
        MyRunnable myRunnable = new MyRunnable();

        // 创建 Thread 对象并传入 MyRunnable 实例
        Thread thread = new Thread(myRunnable);

        // 启动线程
        thread.start();
    }
}

使用Callable和Future创建线程

  1. 创建一个实现Callable接口的类,并重写其call()方法。
  2. 然后使用ExecutorService提交Callable任务,并通过Future对象获取返回结果。

注意:使用 Callable 和 Future 创建线程相比直接使用 Runnable 接口和 Thread 类更为灵活,因为它允许获得线程的执行结果,并能够异步地处理任务。

下面是使用 Callable 和 Future 创建线程的示例代码: 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main implements Callable<String> {
    @Override
    public String call() {
        // 在此处添加想要线程执行的代码逻辑
        return "线程运行结束";
    }

    public static void main(String[] args) throws Exception {
        // 创建 CallableExample 实例
        Main callableExample = new Main();

        // 创建线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // 提交 CallableExample 实例到线程池并返回 Future 对象
        Future<String> future = executor.submit(callableExample);

        // 关闭线程池(可选)
        executor.shutdown();

        // 获取线程执行结果
        String result = future.get();
        System.out.println("线程结果: " + result);//线程结果: 线程运行结束

    }
}

使用Executor框架创建线程池

Executors提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

主要有newFixedThreadPool,newCachedThreadPool,newSingleThreadExecutor,newScheduledThreadPool。

注意,调用 shutdown() 方法后,线程池将不再接受新的任务,并且会等待已提交的任务执行完成。

使用 Executor 框架可以更方便地管理和控制线程池,避免手动创建和启动线程的繁琐操作。

下面是使用 Executor 框架创建线程池的示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        // 创建固定大小的线程池,最多同时执行两个线程
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 提交任务到线程池
        executor.submit(new MyTask("任务1"));
        executor.submit(new MyTask("任务2"));
        executor.submit(new MyTask("任务3"));

        // 关闭线程池
        executor.shutdown();
    }

    static class MyTask implements Runnable {
        private String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("任务 " + name + " 正在执行");
        }
    }
}

执行结果

任务 任务2 正在执行
任务 任务1 正在执行
任务 任务3 正在执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Onlooker﹒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值