java多线程(详)

article/2025/10/9 13:13:44

目录

一,什么叫线程?        那我们要先了解什么叫进程,线程依赖于进程而存在的。

二.多线程的创建

方式一:继承Thread类

方式二:实现Runnable接口

方式三:JDK 5.0新增:实现Callable接口

三种方式的比较

三.线程Thread的常用方法

四.线程调度 

五.线程控制

六.线程的生命周期:

七.线程同步

1.同步代码块:

2.同步方法:

3.lock锁

 八.线程池

1.概念

2.不使用线程池的问题    

3.工作原理

4.如何得到线程池对象

 5.ThreadPoolExecutor构造器的参数说明

6.线程池常见面试题:

作者有话说 


一,什么叫线程?
        那我们要先了解什么叫进程,线程依赖于进程而存在的。

进程:正在运行的程序

  • 是系统进行资源调用和资源分配的独立单位
  • 每一个进程都有它自己的内存空间和系统资源

线程:是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径就是单线程程序

记事本程序:在调出页面设置的时候只能在关闭页面设置之后进行其他操作,否则无法进行其他操作。

  • 多线程:一个进程如果只有多条执行路径就是多线程程序

扫雷程序:点击第一下时间开始计时,时间计时的同时可以玩扫雷游戏

二.多线程的创建

方式一:继承Thread类

  • Java是通过java.lang.Thread 类来代表线程的。(不需要导包)
  • 按照面向对象的思想,Thread类应该提供了实现多线程的方式。

方法:

  1. 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法

为啥要重写run()方法:

        因为在MyThread里面还有其他的代码,并不是所有的代码都需要被线程执行,为了区分哪些被线程执行,java就提供了一个run()方法

  1. 创建MyThread类的对象
  2. 调用线程对象的start()方法启动线程(启动后还是执行run方法的)

优缺点:

优点:编码简单

缺点:线程类已经继承Thread,无法继承其他类,不利于扩展。

/**目标:多线程的创建方式一:继承Thread类实现。*/
public class ThreadDemo1 {public static void main(String[] args) {// 3、new一个新线程对象Thread t = new MyThread();// 4、调用start方法启动线程(执行的还是run方法)//run方法就是一个普通的方法,没有真正启动一个线程,就会把run方法执行完毕,才向下执行,//就是会先执行run方法 只有当run执行完毕才会执行其他线程t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程执行输出:" + i);}}
}/**1、定义一个线程类继承Thread类*/
class MyThread extends Thread{/**2、重写run方法,里面是定义线程以后要干啥*/@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程执行输出:" + i);}}
}

小问题:
        为什么不直接调用了run方法,而是调用start启动线程。

         直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。 只有调用start方法才是启动一个新的线程执行。

方式二:实现Runnable接口

  1. 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
  2. 创建MyRunnable任务对象
  3. 把MyRunnable任务对象交给Thread处理。
  4. 调用线程对象的start()方法启动线程

构造器

说明

public Thread(String name)

可以为当前线程指定名称

public Thread(Runnable target)

封装Runnable对象成为线程对象

public Thread(Runnable target ,String name )

封装Runnable对象成为线程对象,并指定线程名称

优缺点:

优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。

缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。 

/**目标:学会线程的创建方式二,理解它的优缺点。*/
public class ThreadDemo2 {public static void main(String[] args) {// 3、创建一个任务对象Runnable target = new MyRunnable();// 4、把任务对象交给Thread处理Thread t = new Thread(target);// Thread t = new Thread(target, "1号");// 5、启动线程t.start();for (int i = 0; i < 10; i++) {System.out.println("主线程执行输出:" + i);}}
}/**1、定义一个线程任务类 实现Runnable接口*/
class MyRunnable  implements Runnable {/**2、重写run方法,定义线程的执行任务的*/@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("子线程执行输出:" + i);}}
}

方式三:JDK 5.0新增:实现Callable接口

1、前2种线程创建方式都存在一个问题:

         他们重写的run方法均不能直接返回结果。 不适合需要返回线程执行结果的业务场景。

2、怎么解决这个问题呢?

         JDK 5.0提供了Callable和FutureTask来实现。 这种方式的优点是:可以得到线程执行的结果。

3.多线程的实现方案三:利用Callable、FutureTask接口实现。

(1)、得到任务对象

         定义类实现Callable接口,重写call方法,封装要做的事情。

        用FutureTask把Callable对象封装成线程任务对象。

(2)、把线程任务对象交给Thread处理。

(3)、调用Thread的start方法启动线程,执行任务

(4)、线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。

优缺点:
优点:

        线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。

        可以在线程执行完毕后去获取线程执行的结果。

缺点:

        编码复杂一点。 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/**目标:学会线程的创建方式三:实现Callable接口,结合FutureTask完成。*/
public class ThreadDemo3 {public static void main(String[] args) {// 3、创建Callable任务对象Callable<String> call = new MyCallable(100);// 4、把Callable任务对象 交给 FutureTask 对象//  FutureTask对象的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread了//  FutureTask对象的作用2: 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果FutureTask<String> f1 = new FutureTask<>(call);// 5、交给线程处理Thread t1 = new Thread(f1);// 6、启动线程t1.start();Callable<String> call2 = new MyCallable(200);FutureTask<String> f2 = new FutureTask<>(call2);Thread t2 = new Thread(f2);t2.start();try {// 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。String rs1 = f1.get();System.out.println("第一个结果:" + rs1);} catch (Exception e) {e.printStackTrace();}try {// 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。String rs2 = f2.get();System.out.println("第二个结果:" + rs2);} catch (Exception e) {e.printStackTrace();}}
}/**1、定义一个任务类 实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型*/
class MyCallable implements Callable<String>{private int n;public MyCallable(int n) {this.n = n;}/**2、重写call方法(任务方法)*/@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n ; i++) {sum += i;}return "子线程执行的结果是:" + sum;}
}

三种方式的比较

方式

优点

缺点

继承Thread类

编程比较简单,可以直接使用Thread类中的方法

扩展性较差,不能再继承其他的类,不能返回线程执行的结果

实现Runnable接口

扩展性强,实现该接口的同时还可以继承其他的类。

编程相对复杂,不能返回线程执行的结果

实现Callable接口

扩展性强,实现该接口的同时还可以继承其他的类。可以得到线程执行的结果

编程相对复杂

三.线程Thread的常用方法

1. 当有很多线程在执行的时候,我们怎么去区分这些线程呢?

此时需要使用Thread的常用方法:getName()、setName()、currentThread()等。

Thread常用方法、构造器

方法名称

说明

String getName​()

获取当前线程的名称,默认线程名称是Thread-索引

void setName​(String name)

设置线程名称

public static Thread currentThread():

返回对当前正在执行的线程对象的引用

public static void sleep(long time)

让线程休眠指定的时间,单位为毫秒。

public void run()

线程任务方法

public void start()

线程启动方法

构造器

说明

public Thread(String name)

可以为当前线程指定名称

public Thread(Runnable target)

把Runnable对象交给线程对象

public Thread(Runnable target ,String name )

把Runnable对象交给线程对象,并指定线程名称


public class MyThread extends Thread{public MyThread(){}public MyThread(String name){super(name);}public void run(){for(int i=0;i<50;i++){System.out.println(getName()+"追逐王二的速度"+i+"km/h");}}
}public class ThreadDemo1 {public static void main(String[] args) {Thread t=new MyThread("张三");Thread t1=new MyThread("李四");t.start();t1.start();}}

四.线程调度 

线程有两种调度模型 
        ●分时调度模型: 所有线程轮流使用CPU的使用权,平均分配每个钱程占用CPU的时间片 
        ●抢占式调度模型:  抢占式调度模型:优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些 
        Java使用的是抢占式调度模型 
假如计算机只有一个CPU, 那么CPU在某一个时刻只能执行一 条指令, 线程只有得到CPU时间片,也就是使用权, 才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的 

Thread类中设置和获取线程优先级的方法
●public final int getPriority0:返回此线程的优先级
public final void setPriority(int newPriority):更改此线程的优先级

五.线程控制

方法名     说明
static void sleep(long millis)    使当前正在执行的线程停留 (暂停执行) 指定的毫秒数
void join() 等待这个线程死亡
void setDaemon(booleanon)    将此线程标记为守护线程, 当运行的线程都是守护线程时,Java虚拟机将退出

static void sleep(long millis)    :可以让线程1秒内同时开始,然后停止。只有前后的争夺不会连续;

 public void run() {for (int i=0;i<50;i++){System.out.println(getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}

void join() :“李渊”死了之后李世民和李建成才能开始夺位,所以join()是等设置的线程死亡其他线程才能工作。

public static void main(String[] args) {Thread t=new zh01("李渊");Thread t1=new zh01("李世民");Thread t2=new zh01("李建成");t.start();try {t.join();} catch (InterruptedException e) {e.printStackTrace();}t1.start();t2.start();}

void setDaemon(booleanon)  :设置一个主线程,其他守护线程等主线程死亡后,也慢慢停止运行

public class Zh04 {public static void main(String[] args) {zh01  td1 = new zh01  () ;zh01   td2 = new zh01  ( ) ;td1. setName( "关羽");td2. setName("张飞");
//设置主线程为刘备Thread . currentThread(). setName("刘备");
//设置守护线程td1. setDaemon(true);td2. setDaemon(true);td1.start();td2. start();for(int i=0; i<10; i++) {System. out . println(Thread. currentThread() . getName()+":"+i);}}}

六.线程的生命周期:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rW357u1aG9uZw==,size_20,color_FFFFFF,t_70,g_se,x_16

NEW(新建)

线程刚被创建,但是并未启动。

Runnable(可运行)

线程已经调用了start()等待CPU调度

Blocked(锁阻塞)

线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态;。

Waiting(无限等待)

一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒

Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。带有超时参数的常用方法有Thread.sleep 、Object.wait。

Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

七.线程同步

需求:某电影院正在上演一部大片,现有100张票在三个窗口销售,用线程模拟三个窗口的售票速度和票数情况,所以我们用sleep()方法模拟售票等待时机

package 多线程;public class Buypiao extends Thread{public Buypiao(){}public Buypiao(String name){super(name);}private int piao=100;@Overridepublic void run() {while (true){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}if(piao>0){System.out.println(Thread.currentThread().getName()+"销售还有"+piao+"张");piao--;}}}package 多线程;public class Buypiaodomn {public static void main(String[] args) {Buypiao buy=new Buypiao("窗口1");Buypiao buy1=new Buypiao("窗口2");Buypiao buy2=new Buypiao("窗口3");buy.start();buy1.start();buy2.start();}
}

 9e1aba32f13f409d8bf974d2bd0fe729.png

我们发现在运行的时候出现了票数重复 :假设t1线程先抢到cpu的执行权,但是需要休息,这个时候t2抢到cpu的执行权,故此t2也开始执行,t3也是如此;最后才能减少票数

问题分析:

为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准
●是否是多线程环境

是否有共享数据
●是否有多条语句操作共享数据
如何解决多线程安全问题呢?
●基本思想: 让程序没有安全问题的环境
怎么实现呢? .
●把多条语句操作共享数据的代码给锁起来, 让任意时刻只能有一个线程执行即可
●Java提供 了同步代码块的方式来解决


1.同步代码块:

格式:

synchronized (任意对象:相当于一把锁) {

多条语句操作共享语句的代码

}

作用:把出现线程安全问题的核心代码给上锁。

原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。

锁对象的规范要求

规范上:建议使用共享资源作为锁对象。

对于实例方法建议使用this作为锁对象。

对于静态方法建议使用字节码(类名.class)对象作为锁对象。

同步代码块是如何实现线程安全:

对出现问题的核心代码使用synchronized进行加锁

每次只能一个线程占锁进入访问

 public void run() {while (true) {synchronized (obj) {if (piao > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "销售还有" + piao + "张");piao--;}}}}

cf9a5337366f409a85cf22452244d737.png

 问题解决思路:

假设 t1抢到了cpu的执行权,然后t1开始运行,t1休息的时候t2抢到cpu的执行权,因为代码上锁所以只能等待,等t1休息好,这段代码的锁就被释放了,运行完t2才开始执行,这个时候代码也会一步步递减

同步的好处和弊端
●好处:解决了多线程的数据安全问题
●弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

2.同步方法:

        就是把synchronized关键词加到方法上

格式:

        修饰符synchronized返回值类型 方法名(方法参数){ }

同步方法的锁对象:

        this

同步静态方法:就是把synchronized关键词加到静态方法上

格式:

        修饰符static synchronized返回值类型 方法名(方法参数){ }

同步方法的锁对象:

        类名.class

作用:把出现线程安全问题的核心方法给上锁。

原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

底层原理:

同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。

如果方法是实例方法:同步方法默认用this作为的锁对象。

但是代码要高度面向对象! 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。

3.lock锁

为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock,更加灵活、方便。

Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象

方法名称

说明

public ReentrantLock​()

获得Lock锁的实现类对象

方法名称

说明

void lock()

获得锁

void unlock()

释放锁

 while (true) {lock.lock();if (piao > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "销售还有" + piao + "张");piao--;}lock.unlock();}}

 八.线程池

1.概念

         线程池就是一个可以复用线程的技术。

2.不使用线程池的问题    

          如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。

3.工作原理

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rW357u1aG9uZw==,size_20,color_FFFFFF,t_70,g_se,x_16

4.如何得到线程池对象

方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

ExecutorService-->ThreadPoolExecutor

方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象 

 5.ThreadPoolExecutor构造器的参数说明

        watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rW357u1aG9uZw==,size_20,color_FFFFFF,t_70,g_se,x_16

参数一:指定线程池的线程数量(核心线程): corePoolSize--->不能小于0

参数二:指定线程池可支持的最大线程数: maximumPoolSize--->最大数量 >= 核心线程数量

参数三:指定临时线程的最大存活时间: keepAliveTime--->不能小于0

参数四:指定存活时间的单位(秒、分、时、天): unit--->时间单位

参数五:指定任务队列: workQueue--->不能为null

参数六:指定用哪个线程工厂创建线程: threadFactory--->不能为null

参数七:指定线程忙,任务满的时候,新任务来了怎么办: handler --->不能为null

6.线程池常见面试题:

临时线程什么时候创建啊?

        新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。

什么时候会开始拒绝任务?

        核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝。

作者有话说 

咋就是说本来只想写点的结果越写发现线程越神秘,要不是实力受限咋能写本书出来,线程真的有点强了,还有一些写了怕误导大家就不进行反面教材了!!! 谢谢大家支持!!!


http://chatgpt.dhexx.cn/article/0HUg0ZVd.shtml

相关文章

Java线程、Java多线程详细介绍

目录 一、进程和线程的区别 1.1 进程 1.2 线程 二、并发和并行 2.1 并行 2.2 并发 2.3 监控线程的执行情况 三、创建方式 3.1 继承Thread类 思考&#xff1a;为什么不直接通过对象调用start&#xff08;&#xff09;方法&#xff1f; 3.2 实现Runnable接口 …

【java】java多线程及线程池详解

目录 前言线程是什么&#xff1f;多线程是什么&#xff1f;多线程的作用和好处以及缺点守护线程和用户线程并发和并行的区别 一.线程的状态和常用方法1.线程各种状态转化图2.线程相关常用方法有① wait()② sleep(long timeout)③ join()④ yield()⑤ notify()和notifyAll() 3.…

Java线程池(超详细)

文章目录 1. 线程池概念2. JUC线程池架构3. Executors创建线程的4种方法4. 线程池的标准创建方式5. 向线程池提交任务的两种方式6. 线程池的任务调度流程7. ThreadFactory&#xff08;线程工厂&#xff09;8. 任务阻塞队列9. 调度器的钩子方法10. 线程池的拒绝策略11. 线程池的…

Java多线程超详解

引言 随着计算机的配置越来越高&#xff0c;我们需要将进程进一步优化&#xff0c;细分为线程&#xff0c;充分提高图形化界面的多线程的开发。这就要求对线程的掌握很彻底。 那么话不多说&#xff0c;今天本帅将记录自己线程的学习。 程序&#xff0c;进程&#xff0c;线程的…

java多线程(超详细)

1 - 线程 1.1 - 进程 进程就是正在运行中的程序&#xff08;进程是驻留在内存中的&#xff09; 是系统执行资源分配和调度的独立单位 每一进程都有属于自己的存储空间和系统资源 注意&#xff1a;进程A和进程B的内存独立不共享。 1.2 - 线程 线程就是进程中的单个顺序控制…

JAVA线程

一、线程相关概念 &#xff08;一&#xff09;程序、进程和线程的区别 程序 程序是含有指令和数据的文件&#xff0c;被存储在磁盘或其他的数据存储设备中&#xff0c;也就是说程序是静态的代码。 进程 进程是程序的一次执行过程&#xff0c;是系统运行的基本单位&#xf…

Java 线程 基础知识总结

线程基础 很不严谨的说&#xff0c;线程是什么&#xff1f;线程就是为了让很多个东西并发执行&#xff0c;大大的提高程序执行的效率啊 三个非常重要的概念&#xff1a; 程序&#xff1a;一组写好了的静态代码块&#xff08;就我们写的那些代码玩意&#xff09;进程&#xf…

Java多线程(超详解)

目录 1. 线程简介 1.1 程序 1.2 进程 1.3 线程 1.4 多线程 1.5 普通方法调用和多线程 2. 线程创建 2.1 继承Thread类 2.2 实现Runnable接口 2.3 实现Callable接口&#xff08;了解&#xff09; 2.4 网图下载 2.4.1 通过继承Thread类实现网图下载 2.4.2 通…

java 线程详解

一、线程的基本概念 一个程序最少需要一个进程&#xff0c;而一个进程最少需要一个线程。关系是线程–>进程–>程序的大致组成结构。所以线程是程序执行流的最小单位&#xff0c;而进程是系统进行资源分配和调度的一个独立单位。 一个线程就是在进程中的一个单一的顺序…

JAVA多线程详解(超详细)

目录 一、线程简介1、进程、线程2、并发、并行、串行3、进程的三态 二、线程实现1、继承Thread类2、实现Runnable接口3、实现Callable接口&#xff08;不常用&#xff09; 三、线程常用方法1、线程的状态2、线程常用方法 四、多线程1、守护&#xff08;Deamon&#xff09;线程2…

Java多线程(超详细!)

1、什么是进程&#xff1f;什么是线程&#xff1f; 进程是:一个应用程序&#xff08;1个进程是一个软件&#xff09;。 线程是&#xff1a;一个进程中的执行场景/执行单元。 注意&#xff1a;一个进程可以启动多个线程。 eg. 对于java程序来说&#xff0c;当在DOS命令窗口中…

count/count if函数的基本用法

count函数&#xff0c;用来计算单元格的数的个数&#xff0c;只是用来计数&#xff0c;并且只有只记录数子的个数&#xff0c;文本的个数是不被记录的。 但是很少会用到单纯的count函数&#xff0c;往往在工作中计数是带有条件的。就会用到countif函数 COUNTIF函数需要注意的点…

EXCEL COUNTIF()的一些奇特的用法

文章目录 前言一、统计第几次重复二、统计不重复的数量三、通配符模糊统计四、防止重复录入五、忽略错误值或空值统计六、重复值填充背景色总结 前言 日常工作中需要度娘很多知识点或者方法&#xff0c;但每次用了就忘&#xff0c;下次遇到就需要继续度娘&#xff0c;故在此记…

Excel多条件计数——COUNTIFS【获奖情况统计】

问题描述 当前&#xff0c;我们需要对表格中的获奖情况进行统计 奖励级别&#xff1a;院级、校级、国家级、国际级奖励内容&#xff1a;特等奖、一等奖、二等奖、三等奖、优胜奖 功能要求 对所有奖励级别进行统计根据级别&#xff0c;计算内容数量 当有人的选项内容如下时 …

如何在Microsoft Excel中使用COUNTIF函数

COUNTIF 是一个 Excel 函数,用于对满足单个条件的区域中的单元格进行计数。COUNTIF可用于计算包含日期、数字和文本的单元格。COUNTIF 中使用的条件支持逻辑运算符(>、<、<>、=)和通配符(*、?)进行部分匹配。 例如,我们想计算包含 Google或 Facebook 的单元…

COUNT函数的使用

一、问题描述 今天在随手练习sql的时候&#xff0c;发现count查出来的数量和实际的数量不对&#xff0c;下面是我查询的sql 我想看看suitName字段一共有多少种数据 SELECTCOUNT(DISTINCT suitName) AS suitNameNum FROMrace_goods 得到的结果是suitName条数是22条&#xff0c…

countif是什么意思,如何运用?

countif是什么意思&#xff1f;countif函数是excel中对指定区域中符合指定条件的单元格计数的一个函数&#xff0c;简单来说就是算出某个参数的数量。那么&#xff0c;countif函数具体是如何运用的呢&#xff1f;小编分为两种情景为大家总结了操作步骤。 情景一&#xff1a;计算…

excel通过sumproduct和countifs不重复计数(数据中包含空白单元)

1. 常规情况&#xff0c;数据中不包含空白单元格&#xff0c;如下图&#xff1a; SUMPRODUCT((A2:A24E2)*(B2:B24F2)*(1/COUNTIFS(A2:A24,A2:A24,B2:B24,B2:B24,C2:C24,C2:C24))) 2. 数据中包含空白单元格&#xff0c;如下图&#xff1a; 数据中包含空白单元的情况&#xff0c…

countif怎么读(countif怎么读)

SUM,AVERAGE,MAX,MIN,PRODUCT,CUONT,RANK,IF,SUMIF,COUNTIF怎么读呀&#xff01;谢谢 SUM(桑母) 求和函数&#xff1b; AVERAGE(哎五瑞之) 求平均数函数&#xff1b; MAX(麦克斯) 最大值函数&#xff1b; MIN(民) 最小值函数&#xff1b; PRODUCT(普若达克特) 求积函数&#xf…

[Excel常用函数] countif countifs函数

countif函数 1.countif函数的含义 在指定区域中按指定条件对单元格进行计数&#xff08;单条件计数&#xff09; 2.countif函数的语法格式 countif&#xff08;range&#xff0c;criteria&#xff09; 参数range 表示条件区域——对单元格进行计数的区域。 参数criteria …