java实现多线程的四种方式

简述多线程概念

        1.什么是多线程?

                有了多线程,我们可以让程序同事做多件事情。

        2.多线程的作用?

                提高效率

        3.多线程的应用场景

                只要你想让多个事情同事运行就需要用到多线程。

                比如软件中耗时操作、所有的软件聊天、所有的服务器。

并发和并行?

        并发:在同一时刻,有多个指令在单个cpu上交替执行

                在玩游戏的时候,你的右手一会抽烟、一会喝可乐、一会按鼠标,来回操作

                此时,右手相当于CPU、鼠标、可乐、抽烟相当于线程n

                

                如上图 线程一会执行右边的指令 一会执行右边的指令

        并行:同一时刻,有多个指令在多个cpu上同时执行      

        如左图,两个线程同时处理连个指令

    一般CPU有分为n和m线程,m的数量代表了他能同时处理的数量,当同时处理的线程数达到最大时,此时就会进行交替处理。

多线程的实现方式

线程(Thread)是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或者不可以标记一个守护程序。当某人线程中的运行代码创建一个新的Thread对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当java虚拟机启动时,通常会有当个非守护线程(它通常会调用某个指定类的main方法)。java虚拟机会继续执行线程,知道下列任一情况出现为止。

       ·调用了runtime类的exit方法,并且安全管理器允许退出操作发生

        ·非守护线程的所有线程都已停止运行,无论是通过从对run方法的调用中返回,还是通过抛出一个传播到run方法之外的异常。

第一种 继承Thread类 重写run方法:

1.定义一个类,继承了Thread(本质上是实现了runnable接口),重写run方法。
2.通过Thread.start()方法(且一个线程只允许调佣一次)启动线程。
        ·Thread.start方法是native方法(只有方法名,没有方法体)
        ·继承Thread类无法在继承其他业务类

        ·此方法无法获取返回值

package com.ruoyi.web.controller.thread;


/**
 * 多线程四种处理方式 -- 第一种 继承Thread类 重写run方法
 *
 * @author zhuang.bq
 * @create 2024/5/13  9:13
 * @desc
 **/
public class MyThread1 extends Thread {


    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            String threadName = MyThread1.currentThread().getName();
            System.out.println(threadName + ".start");
        }
    }

    public static void main(String[] args) {
        MyThread1 thread1 = new MyThread1();
        thread1.setName("线程1");
        thread1.start();
        MyThread1 thread2 = new MyThread1();
        thread2.setName("线程2");
        thread2.start();
    }
}

从执行的结果可以看到线程在交替运行。

第二种 实现runnable接口方式实现

        1.定义一个类,实现Runable接口(避免单继承的局限性),重写run方法(子类负责业务逻辑,thread负责资源调度及线程创建辅助处理业务)
        2.创建类对象,创建一个Thread类对象并开启线程

        3.同上,此方法无法获取返回值

package com.ruoyi.web.controller.thread;

/**
 * 实现runnable接口方式实现
 *
 * @author zhuang.bq
 * @create 2024/5/13  15:57
 * @desc
 **/
public class MyRun1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + ".run");
        }
    }

    public static void main(String[] args) {
        MyRun1 myRun1 = new MyRun1();//创建run对象 表示需要执行的任务
        Thread t1 = new Thread(myRun1);//创建线程对象,并将自定义线程丢进去
        t1.setName("线程1");
        t1.start();//开启线程
        Thread t2 = new Thread(myRun1);
        t2.setName("线程2");
        t2.start();

    }


}

从执行的结果可以看到线程在交替运行。

第三种 利用callable接口和Future接口方式实现

1.定义一个类实现Callable接口,并重写call方法(call方法有返回值<T>)
2.创建Callable实现类的对象
3.创建FutureTask对象(作用管理多线程运行结果),并将Callable对象传递给FutureTask
4.创建Thread对象,将FutureTask对象传递给Thread,并启动线程Thread.start
5.调用FutrueTask对象的get()方法获取返回结果 

package com.ruoyi.web.controller.thread;

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

/**
 * 利用callable接口和Future接口方式实现
 * 
 * @author zhuang.bq
 * @create 2024/5/13  16:09
 * @desc
 **/
public class MyCallAble implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+".call");
        int sum = 0;
        for (int i = 0; i < 1000; i++) {
            sum = sum + i;
        }
        return sum;
    }

    public static void main(String[] args) {
        MyCallAble myCallAble = new MyCallAble();
        FutureTask<Integer> task = new FutureTask(myCallAble);
        Thread t1 = new Thread(task);
        t1.setName("线程1");
        t1.start();//开启线程
        try {
            Integer ret = task.get();
            //获取多线程运行的结果
            System.out.println("call.ret:"+ret);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        FutureTask<Integer> task2 = new FutureTask(myCallAble);
        Thread t2 = new Thread(task2);
        t2.setName("线程2");
        t2.start();//开启线程
        try {
            Integer ret = task2.get();
            //获取多线程运行的结果
            System.out.println("call.ret:"+ret);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

第四种 通过线程池启动多线程

通过Executor的工具类可以创建三种类型的普通线程池(固定大小线程池、缓存线程池、单线程池)
 

单线程池:SingleThreadPoolExecutor,用于需要固定执行顺序的业务场景

package com.ruoyi.web.controller.thread;

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

/**
 * 单线程池
 *
 * @author zhuang.bq
 * @create 2024/5/13  17:17
 * @desc
 **/
public class MyExecutor1 {

    public static void main(String[] args) {
        ExecutorService ex = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 3; i++) {
            ex.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 5; j++) {
                        System.out.println(Thread.currentThread().getName()+j);
                    }
                }
            });
        }
        ex.shutdown();
    }
}

        

固定大小线程池:FixThreadPool,根据服务器资源来固定设置线程池大小,用于负载比较重的服务器。

        

package com.ruoyi.web.controller.thread;

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

/**
 * 单线程池
 *
 * @author zhuang.bq
 * @create 2024/5/13  17:17
 * @desc
 **/
public class MyExecutor2 {

    public static void main(String[] args) {
        ExecutorService ex = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 3; i++) {
            ex.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 5; j++) {
                        System.out.println(Thread.currentThread().getName() + j);

                    }
                }
            });
        }
        ex.shutdown();
    }
}

  缓存线程池:CashedThreadPool,当提交任务速度高于线程池中的任务处理速度时,缓存线程池会不断的创建线程, 适用于提交短期的异步小程序,以及负载较轻的服务器
package com.ruoyi.web.controller.thread;

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

/**
 * 单线程池
 *
 * @author zhuang.bq
 * @create 2024/5/13  17:17
 * @desc
 **/
public class MyExecutor3 {

    public static void main(String[] args) {
        ExecutorService ex = Executors.newCachedThreadPool();
        for (int i = 0; i < 3; i++) {
            ex.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 5; j++) {
                        System.out.println(Thread.currentThread().getName() +" "+ j);

                    }
                }
            });
        }
        ex.shutdown();
    }
}

以上四种方式优缺点:

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zbqice007

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

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

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

打赏作者

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

抵扣说明:

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

余额充值