Java--多线程基础

文章介绍了操作系统如何通过多任务机制使得单核CPU也能执行多个任务,解释了进程作为资源分配单位和线程作为执行单位的概念。线程是进程内的更小执行单元,一个进程可包含多个线程。文章还讨论了线程与进程的区别,包括资源开销、内存分配和影响关系。最后,通过Java示例展示了线程的创建,包括继承Thread类、实现Runnable接口和实现Callable接口的方法。

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

一、概述


        现代操作系统(Windows,macOS,Linux)都可以执行多任务。多任务就是同时运行多个任务。
        CPU执行代码都是一条一条顺序执行的,但是,即使是单核CPU,也可以同时运行多个任务。因为操作系统执行多任务实际上就是让CPU对多个任务轮流交替执行。
操作系统轮流让多个任务交替执行,例如,让浏览器执行0.001秒,让QQ执行0.001秒,再让音乐播放器执行0.001秒。在用户使用的体验看来,CPU就是在同时执行多个任务。

二 、 线程与进程

        1、 进程

        进程是程序的一次执行过程,是系统运行程序的基本单位。在Windows系统中,每一个正在执行的exe文件或后台服务,都是一个进程,由操作系统统一管理并分配资源,因此进程是动态的。 例如:正在运行中的浏览器就是一个进程,正在运行中的音乐播放器是另一个进程,同理,正在运行中的QQ和WPS等都是进程。
        操作系统运行一个程序,即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着, 同时,每个进程还占有某些系统资源如 CPU时间,内存空间,文件,输入输 出设备的使用权等。

        2、 线程

        某些进程内部还需要同时执行多个子任务。例如,我们在使用WPS时,WPS可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行自动保存和上传云文档,我们把子任务称为线程。线程是进程划分成的更小的运行单位。

       3、 线程与进程的关系

           一个进程可以包含一个或多个线程,但至少会有一个主线程。
   

         4、 线程与进程的区别

        (1)根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位;
        (2)资源开销:每个进程都有独立的代码副本和数据空间,进程之间的切换,资源开销较大;线程可以看做轻量级的进程,每个线程都有自己独立的运行栈和程序计数器,线程之间切换,资源开销小;
        (3)包含关系:一个进程内包含有多个线程,在执行过程,线程的执行不是线性串行的,而是多条线程并行共同完成;
        (4)内存分配:同一进程内的所有线程共享本进程的内存空间和资源;进程之间的内存空间和资源相互独立;
        (5)影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响;一个线程崩溃,会导致整个进程退出。所以多进程要比多线程健壮;
        (6)执行过程:每个独立的进程有程序运行的入口和程序出口。但是线程不能独立执行,必须依存在应用程序(进程)中,由应用程序提供多个线程执行控制;

三、 线程基本概念

        1、 单线程:单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。

        2、 多线程:由一个以上的线程组成的程序称为多线程程序。Java中,一定是从主线程开始执行(main方法),然后在主线程的某个位置创建并启动新的线程。

四、 线程的创建方法

        (一)、方式一:继承  java.lang.Thread 类(线程子类)

public class SubThread extends Thread{
    
    public SubThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for(char c = 'A' ; c <= 'Z' ; c++) {
            System.out.printf("[%s]:%s\n",this.getName(),c);
            
        }
    }
    
}

public class test01 {
    public static void main(String[] args) {
        System.out.println("主线程开始……");
        
        // 创建子线程1(继承Thread类)
        Thread t1 = new Thread("线程1") {

            @Override
            public void run() {
                for(int i = 1 ; i <100 ; i++) {
                    System.out.printf("线程1中的%s被执行",i);
                    System.out.println();
                }
            }
            
        };
        t1.start();
        Thread t2 = new Thread("线程2") {

            @Override
            public void run() {
                for(char c = 'A' ; c<='X';c++) {
                    System.out.printf("线程2中的%s被执行",c);
                    System.out.println();
                }
            }
            
        };
        t2.start();
        System.out.println("主线程执行结束!");
    
    }
}

(二)、方式二:实现  java.lang.Runnable 接口(线程执行类)

// 线程创建方式2 : 实现Runnable接口
public class test03 {
    public static void main(String[] args) {
        // 每个Runnable接口的实现类 ,封装了线程的执行逻辑
        EmailTask emailTask = new EmailTask();
        
        // 创建3个线程,分别发送邮件
        Thread t1 = new Thread(emailTask,"线程t1");
        Thread t2 = new Thread(emailTask,"线程t2");
        Thread t3 = new Thread(emailTask,"线程t3");
        
        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

//父类任务
abstract class Task {
    public abstract void execute();
}

//子类(邮件任务)
class EmailTask extends Task implements Runnable {

    @Override       
    public void run() {
        execute();
    }

    @Override
    public void execute() {
        // 获取当前线程对象
        Thread currentThread = Thread.currentThread();

        // 获取线程名称
        String threadName = currentThread.getName();

        System.out.println(threadName + ":我去上学校,天天不迟到~");
    }
}

(三)、 方式三:实现  java.util.concurrent.Callable 接口,允许子线程返回结果、抛出异常

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

// 线程创建方式3 : 实现Callable接口
public class test04{
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // Callable接口实现类:不同数据范围的计算任务
        SumCalcTask task1 = new SumCalcTask(1,300);//1-300
        SumCalcTask task2 = new SumCalcTask(301,500);//301,500
        SumCalcTask task3 = new SumCalcTask(501,1000);//501,1000
        
        // Callable --> FutureTask(Runnable接口实现类)
        FutureTask<Integer> futureTask1 = new FutureTask<Integer>(task1);
        FutureTask<Integer> futureTask2 = new FutureTask<Integer>(task2);
        FutureTask<Integer> futureTask3 = new FutureTask<Integer>(task3);

        // 创建并启动线程
        Thread t1 = new Thread(futureTask1);
        Thread t2 = new Thread(futureTask2);
        Thread t3 = new Thread(futureTask3);
    
        // 线程启动
        // futureTask1.run();  -->
        // callable.call(); --> 结果  - -> outcome
        t1.start();
        t2.start();
        t3.start();
    
        // 线程执行结束,分别获取各自线程的返回结果
        System.out.println("开始分别获取……");
        Integer sum1 = futureTask1.get();
        Integer sum2 = futureTask2.get();
        Integer sum3 = futureTask3.get();
    
        System.out.printf("【线程%s】: %d\n",t1.getName(),sum1);
        System.out.printf("【线程%s】: %d\n",t2.getName(),sum2);
        System.out.printf("【线程%s】: %d\n",t3.getName(),sum3);
        
        
        // 汇总
        System.out.println("汇总各自的计算结果:");
        Integer result = sum1 + sum2 + sum3;
        System.out.println("最终计算结果 : " + result);
    }
}


// 通过Callable接口实现类SumCalcTask封装某个范围内数据的累加和
class SumCalcTask implements Callable<Integer>{
    private int begin,end;
    
    public SumCalcTask(int begin , int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    public Integer call() throws Exception {
        int total = 0 ; 
        for(int i = begin; i<= end ; i++) {
            total += i;
        }
        return total;
    }
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值