Java学习-----如何创建线程

        在多线程编程中,创建线程是实现并发操作的基础。不同的编程语言和开发环境提供了多种创建线程的方式,每种方式都有其独特的原理、作用、优缺点。下面将详细介绍几种常见的创建线程的方式。​

(一)继承 Thread 类​

        在 Java 中,Thread 类是线程操作的核心类,继承 Thread 类创建线程是一种基础方式。通过创建一个继承 Thread 类的子类,并重写其 run () 方法,然后实例化该子类对象,调用 start () 方法即可启动线程。​

        Thread 类实现了 Runnable 接口,其中 run () 方法是线程的执行体。当调用 start () 方法时,Java 虚拟机会为该线程分配 CPU 资源等,使其进入就绪状态,当得到 CPU 时间片后,就会执行 run () 方法中的代码。​这种方式可以方便地创建线程,通过重写 run () 方法定义线程要执行的任务,实现线程的并发执行。​

        Thread的优点主要有:​实现简单,直接继承 Thread 类,重写 run () 方法即可,无需额外实现接口。​

        而缺点则主要有:Java 是单继承机制,一个类继承了 Thread 类后,就不能再继承其他类,灵活性较差。​

        下面用一个案例简单的实现一下该继承方式:

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.setName("线程1");
        thread.start();
    }
}

        在上述代码中,MyThread 类继承了 Thread 类,并重写了 run () 方法,在 run () 方法中定义了线程要执行的循环打印任务。在 main 方法中,创建了 MyThread 类的实例,设置线程名称后调用 start () 方法启动线程,线程启动后会执行 run () 方法中的内容。​

(二)实现 Runnable 接口​​

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

        Runnable 接口中只包含一个 run () 方法,它定义了线程要执行的任务。当将实现了 Runnable 接口的对象传递给 Thread 类后,Thread 类的 run () 方法会调用该对象的 run () 方法,从而实现线程的执行。​这种方式可以让多个线程共享同一个实现了 Runnable 接口的对象,从而共享资源,提高资源的利用率。​

        其优缺点主要为:​

        优点:一个类可以同时实现多个接口,不影响其继承其他类,灵活性高;多个线程可以共享一个 Runnable 实例,适合多个线程处理同一份资源的场景。​

        缺点:相对于继承 Thread 类,实现过程稍显复杂,需要多一步将 Runnable 实例传递给 Thread 类的操作。​

        还是一样,用一个简单的案例来实现一下这个方法:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);
        }
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread1 = new Thread(runnable, "线程1");
        Thread thread2 = new Thread(runnable, "线程2");
        thread1.start();
        thread2.start();
    }
}

        上述代码中,MyRunnable 类实现了 Runnable 接口,重写了 run () 方法。在 main 方法中,创建了 MyRunnable 实例,然后将其作为参数分别传递给两个 Thread 对象,设置不同的线程名称后启动线程。两个线程会共享 MyRunnable 实例,共同执行 run () 方法中的任务。​

(三)实现 Callable 接口​

        Callable 接口是 Java 5 中引入的,与 Runnable 接口类似,但它可以返回线程执行的结果,并且可以抛出异常。实现 Callable 接口创建线程时,需要与 FutureTask 类配合使用。​

        Callable 接口中的 call () 方法是线程的执行体,该方法有返回值且可以抛出异常。FutureTask 类实现了 Future 接口和 Runnable 接口,它可以接收 Callable 对象作为参数。当将 FutureTask 对象传递给 Thread 类并启动线程后,线程会执行 call () 方法,执行结果会被 FutureTask 保存,通过 FutureTask 的 get () 方法可以获取该结果。​​这种方式适合需要获取线程执行结果的场景,能够方便地处理线程执行过程中可能出现的异常。​

        Callable优缺点​主要有

        优点:可以获取线程执行结果,能抛出异常,功能更强大;同样遵循面向接口编程思想,不影响类的继承,灵活性高。​

        缺点:实现过程相对复杂,需要结合 FutureTask 类使用,获取结果的 get () 方法可能会阻塞当前线程。​

        下面是其的一个简单案例

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 5; i++) {
            sum += i;
            System.out.println("线程" + Thread.currentThread().getName() + "执行:" + i);
        }
        return sum;
    }
}

public class CallableTest {
    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask, "线程1");
        thread.start();
        try {
            int result = futureTask.get();
            System.out.println("线程执行结果:" + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

        在该案例中,MyCallable 类实现了 Callable接口,重写了 call () 方法,该方法计算 1 到 5 的和并返回。创建 FutureTask 对象时将 MyCallable 实例传入,再将 FutureTask 对象作为参数创建 Thread 对象并启动线程。通过 futureTask.get () 方法可以获取 call () 方法的返回结果,该方法会阻塞当前线程直到获取到结果。​

(四)使用线程池​

        线程池是一种线程管理机制,它预先创建一定数量的线程,当有任务需要执行时,从线程池中取出一个线程来执行任务,任务执行完成后,线程不会被销毁,而是返回到线程池中等待下一个任务。使用线程池创建线程,其实是从线程池中获取线程来执行任务。​

        线程池内部维护了一个线程队列和任务队列。当提交任务时,如果线程池中有空闲线程,则立即执行任务;如果没有空闲线程,且当前线程数量未达到线程池的最大容量,则创建新线程执行任务;如果达到最大容量,则将任务放入任务队列等待,当有线程空闲时,再从任务队列中取出任务执行。​线程池可以减少线程的创建和销毁带来的开销,提高系统的性能和资源利用率,同时可以对线程进行统一管理和控制。​

        线程池的优缺点主要有:​

        优点:降低资源消耗,提高响应速度,便于线程管理(如控制最大并发数等)。​

        缺点:线程池的参数设置需要根据实际情况进行调整,设置不当可能会影响性能;对于一些简单的任务,使用线程池可能会增加一定的复杂性。​

        下面是一个简单的线程池实现:

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

class MyTask implements Runnable {
    private int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("任务" + taskId + "由线程" + Thread.currentThread().getName() + "执行");
    }
}

public class ThreadPoolTest {
    public static void main(String[] args) {
        // 创建一个固定大小为3的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            executorService.submit(new MyTask(i));
        }
        // 关闭线程池
        executorService.shutdown();
    }
}

        在上面的代码中,我们通过 Executors.newFixedThreadPool (3) 创建了一个固定大小为 3 的线程池。然后循环提交 5 个 MyTask 任务到线程池,线程池会从内部的线程中分配线程来执行这些任务。任务执行完成后,线程会返回到线程池中。最后调用 shutdown () 方法关闭线程池。​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值