多线程的四种实现方式

本文详细介绍了Java中实现多线程的四种方法:继承Thread类、实现Runnable接口、使用Callable接口以及利用线程池。特别强调了线程池的优势,如降低资源消耗、提高响应速度和可管理性,并提供了相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 继承Thread类实现多线程
  2. 利用Runnable接口实现多线程
  3. Callable实现多线程
  4. 利用线程池来实现多线程

继承Thread类实现多线程

自定义的类继承Thread类后,覆写父类中的run方法,通过start方法来调用run方法启动线程

简单写下代码:

public class Main{
    public static void main(String args[]) {

        //创建了三个线程
        myThread myThread1=new myThread("thread1");
        myThread myThread2=new myThread("thread2");
        myThread myThread3=new myThread("thread3");

        //通过start方法来调用run方法
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

class myThread extends Thread{
    private String name;
    public myThread(String name){
        this.name=name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name+"  i="+i);
        }
    }
}

利用Runnable接口实现多线程

Runnable接口解决了单继承的问题

自定义一个类继承 Runnable 接口,实现 run 方法,通过 Thread 中的 public Thread ( Runnable target ) 方法来使用 start 方法启动线程,否则无法启动线程

注意:多线程的启动永远使用的是Thread的start方法

public class Main{
    public static void main(String args[]) {
        myThread myThread1=new myThread("thread1");
        myThread myThread2=new myThread("thread2");
        myThread myThread3=new myThread("thread3");
        new Thread(myThread1).start();
        new Thread(myThread2).start();
        new Thread(myThread3).start();
    }
}

class myThread implements Runnable{
    private String name;
    public myThread(String name){
        this.name=name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name+"  i="+i);
        }
    }
}

Callable实现多线程

先看Callable的继承树:
在这里插入图片描述
Callable接口和Thread类并不是直接有联系,所以使用Callable接口要借助FutureTask,FutureTask可以保证任务在多线程的情况下只被一个线程执行一次,
FutureTask中的get方法可以得到call方法的返回值,这也是FutureTask和以上两种方法的不同点,它具有返回值

简单看下代码:

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

public class Main{
    public static void main(String args[]) throws ExecutionException, InterruptedException {
        FutureTask<String> futuretask=new FutureTask<>(new myThread());
        Thread thread1=new Thread(futuretask);
        Thread thread2=new Thread(futuretask);
        thread1.start();
        thread2.start();
        System.out.println(futuretask.get());

    }
}

class myThread implements Callable<String> {
    private int ticket=10;
    @Override
    public String call() throws Exception {
        while (ticket>0){
            System.out.println("剩余票数:"+ticket--);
        }
        return "票已售罄";
    }
}

利用线程池来完成多线程

线程池的实现原理:

  1. 向线程池里提交了一个任务,首先判断线程池的数量是否已达到corePollSize,若没达到,则放入执行任务,若已达到,判断是否有空闲线程,若有,执行任务,若没有,进入下一步
  2. 判断当前线程池的数量有没有达到当前线程池的最大数量,若没有,则放入任务,否则进入下一步
  3. 判断阻塞队列是否已满,若未满,放入阻塞队列中等待调度,否则,进入下一步
  4. 调用相应的拒绝策略打回任务(有四种拒绝策略,默认扔出AbortPolicy异常)

内置的四大线程池:

  1. 固定大小线程池:FixedThreadPool,适用于负载较重的服务器,来满足资源分配的要求
  2. 单线程池:SingleThreadPoolExecutor,只有一个线程,在多线程场景下需要让任务串行执行
  3. 缓存线程池:CachedThreadPool,适用于负载较轻的服务器,或执行很多的短期异地任务
  4. 定时调度池:ScheduledThreadPoolExecutor,适用在给定的延迟之后运行任务,或者定期执行任务

创建线程池:

public ThreadPoolExecutor(int corePoolSize,
             int maximumPoolSize,
             long keepAliveTime,
             TimeUnit unit,
             BlockingQueue<Runnable> workQueue,
             RejectedExecutionHandler handler)

向线程池提交任务有两种方法:

  1. execute() ,提交不需要返回值的任务,无法判断任务是否被线程池执行成功
  2. submit(),提交需要返回值的任务,线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值

关闭线程池有两种方法:

  1. shutdown,只是将线程池的状态设置成SHUTDOWN,然后中断所有没有正在执行任务的线程
  2. shutdownNow,将线程池的状态设置成了STOP,然后停止所有任务,并返回等待执行任务的列表

简单写下代码:

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main{
    public static void main(String args[]) {
        myThread mythread=new myThread();
        ThreadPoolExecutor threadPoolExecutor=
                new ThreadPoolExecutor
                (3,5,2000,TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<Runnable>());
        for (int i = 0; i < 5; i++) {
            threadPoolExecutor.execute(mythread);
        }
        threadPoolExecutor.shutdownNow();
    }
}

class myThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }
}

在实现多线程时,推荐使用线程池来实现

线程池的优点:

  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁带来的消耗
  • 提高响应速度:当任务到达时,任务可以不需要等待线程创建就能立即执行
  • 提高线程的可管理性:使用线程池可以统一进行线程分配、调度和监控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值