java 线程详解

article/2025/10/9 14:44:42

一、线程的基本概念

一个程序最少需要一个进程,而一个进程最少需要一个线程。关系是线程–>进程–>程序的大致组成结构。所以线程是程序执行流的最小单位,而进程是系统进行资源分配和调度的一个独立单位。

一个线程就是在进程中的一个单一的顺序控制流.
而单个进程可以拥有多个并发执行的任务,每个任务都好像有自己的CPU一样,而其底层的机制就是切分CPU的时间,也就是CPU将轮流给每个任务分配其占用时间。
每个任务都觉得自己在一直占用CPU,而事实上是将CPU时间划分成片段分配给所有的任务。
在多个CPU的环境下,多线程的运作,可以极大的提供程序的运行速度,这就是线程存在的意义。

二、线程的实现方式

一、继承Thread类创建线程类

(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。

 public class MYThread extends Thread{@Overridepublic void run() {super.run();}}

二、通过Runnable接口创建线程类

(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。

Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)

	new Thread(new Runnable() {@Overridepublic void run() {}}).start();

三、通过Callable和Future创建线程

(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

/*** Java中创建线程方式三:Callable和FutureTask结合使用*/
public class CallableTest implements Callable{@Overridepublic Object call() throws Exception {int i = 1000;for ( ; i < 1010; i++) {System.out.println(i);}return 1111;}public static void main(String[] args) {CallableTest callableTest = new CallableTest();FutureTask<Integer> futureTask = new FutureTask<Integer>(callableTest);Thread thread = new Thread(futureTask);thread.start();try {System.out.println("Result:"+futureTask.get());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

Future一共给我们提供了三种功能:

  1. 能够取消任务。
  2. 判断任务是否完成。
  3. 能够获取任务执行结果。

四、 三种方式对比

采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

劣势是:编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:线程类已经继承了Thread类,所以不能再继承其他父类。

三.线程的状态

正常线程的五大状态 :新建状态,就绪状态,运行状态,阻塞状态,死亡状态

  1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
  2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的成为“运行”。
    线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得cpu 时间片后变为运行中状态(running)。
    注意:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中
  3. 阻塞(BLOCKED):线程在获取synchronized排他锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
  4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作线程显式地唤醒(通知或中断)。
  5. 限期等待(Timed Waiting)状态:该状态不同于WAITING,处于这种状态的线程也不会被分配CPU执行时间,不过无须等待其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。
  6. 死亡(Dead)状态: 线程执行完了或者因异常退出了run()方法,该线程生命周期结束。

这里写图片描述
在这里插入图片描述

常用方法介绍
1、sleep()
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。

例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了。
总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

2、join()
join()方法使调用该方法的线程在此之前执行完毕,也就是等待该方法的线程执行完毕后再往下继续执行。注意该方法也需要捕捉异常。
thread.join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
3、yield()

该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

4、wait()和notify()、notifyAll()
这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用。synchronized关键字用于保护共享数据,阻止其他线程对共享数据的存取,但是这样程序的流程就很不灵活了,如何才能在当前线程还没退出synchronized数据块时让其他线程也有机会访问共享数据呢?此时就用这三个方法来灵活控制。

wait()方法使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。当调用notify()方法后,将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。

notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。

四.线程同步

为何要使用同步?

java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),
将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用, 从而保证了该变量的唯一性和准确性。

锁类型

  1. 可重入锁:在执行对象中所有同步方法不用再次获得锁
  2. 可中断锁:在等待获取锁过程中可中断
  3. 公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
  4. 读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写

常用同步方法比较:
在这里插入图片描述
ReentrantLock ReentrantLock是Lock接口的实现

  1. ReentrantLock是JDK方法,需要手动声明上锁和释放锁,因此语法相对复杂些;如果忘记释放锁容易导致死锁
  2. 锁的获取: 分情况而定,Lock有多个锁获取的方式,大致就是可以尝试获得锁,线程可以不用一直等待
  3. 锁的状态:可以判断
  4. 锁的类型:可重入 可中断 可公平(两者皆可)
  5. 性能 Lock: 大量同步 Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)

在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
6. ReentrantLock具有更好的细粒度,可以在ReentrantLock里面设置内部Condititon类,可以实现分组唤醒需要唤醒的线程

Synchronized

  1. Synchoronized是JVM方法,由编辑器保证枷锁和释放,在发生异常时候会自动释放占有的锁,因此不会出现死锁
  2. 锁的获取:假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待
  3. 锁的状态:无法判断
  4. 锁的类型: 可重入 不可中断 非公平

一、两种锁的底层实现方式:
synchronized:底层使用指令码方式来控制锁的,映射成字节码指令就是增加来两个指令:monitorenter和monitorexit。当线程执行遇到monitorenter指令时会尝试获取内置锁,如果获取锁则锁计数器+1,如果没有获取锁则阻塞;当遇到monitorexit指令时锁计数器-1,如果计数器为0则释放锁。

Look底层主要靠volatile和CAS操作实现的,底层是CAS乐观锁,依赖AbstractQueuedSynchronizer类,把所有的请求线程构成一个CLH队列。而对该队列的操作均通过Lock-Free(CAS)操作

二、在jdk1.6~jdk1.7的时候,synchronized优化:
1、线程自旋和适应性自旋
我们知道,java’线程其实是映射在内核之上的,线程的挂起和恢复会极大的影响开销。并且jdk官方人员发现,很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能。
而适应性自旋,是赋予了自旋一种学习能力,它并不固定自旋10次一下。他可以根据它前面线程的自旋情况,从而调整它的自旋,甚至是不经过自旋而直接挂起。
2、锁消除:把不必要的同步在编译阶段进行移除。
3、锁粗化
4、轻量级锁
5、偏向锁

1.同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

代码如: 
public synchronized void save(){}

注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

2.同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

代码如: 
synchronized(object){ 
}
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 代码实例: 
package com.xhj.thread;/*** 线程同步的运用* * @author XIEHEJUN* */public class SynchronizedThread {class Bank {private int account = 100;public int getAccount() {return account;}/*** 用同步方法实现* * @param money*/public synchronized void save(int money) {account += money;}/*** 用同步代码块实现* * @param money*/public void save1(int money) {synchronized (this) {account += money;}}}class NewThread implements Runnable {private Bank bank;public NewThread(Bank bank) {this.bank = bank;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {// bank.save1(10);bank.save(10);System.out.println(i + "账户余额为:" + bank.getAccount());}}}/*** 建立线程,调用内部类*/public void useThread() {Bank bank = new Bank();NewThread new_thread = new NewThread(bank);System.out.println("线程1");Thread thread1 = new Thread(new_thread);thread1.start();System.out.println("线程2");Thread thread2 = new Thread(new_thread);thread2.start();}public static void main(String[] args) {SynchronizedThread st = new SynchronizedThread();st.useThread();}}

3.使用特殊域变量(volatile)实现线程同步

a.volatile关键字为域变量的访问提供了一种免锁机制, 
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新, 
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值 
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 例如: 在上面的例子当中,只需在account前面加上volatile修饰,即可实现线程同步。 代码实例: 
      //只给出要修改的代码,其余代码与上同class Bank {//需要同步的变量加上volatileprivate volatile int account = 100;public int getAccount() {return account;}//这里不再需要synchronized public void save(int money) {account += money;}}
注:多线程中的非同步问题主要出现在对域的读写上,如果让域自身避免这个问题,则就不需要修改操作该域的方法。 
用final域,有锁保护的域和volatile域可以避免非同步的问题。 

4.使用重入锁实现线程同步

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。 
ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力ReenreantLock类的常用方法有:ReentrantLock() : 创建一个ReentrantLock实例 lock() : 获得锁 unlock() : 释放锁 
注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 例如: 在上面例子的基础上,改写后的代码为: 代码实例: 
//只给出要修改的代码,其余代码与上同class Bank {private int account = 100;//需要声明这个锁private Lock lock = new ReentrantLock();public int getAccount() {return account;}//这里不再需要synchronized public void save(int money) {lock.lock();try{account += money;}finally{lock.unlock();}}}
注:关于Lock对象和synchronized关键字的选择: a.最好两个都不用,使用一种java.util.concurrent包提供的机制, 能够帮助用户处理所有与锁相关的代码。 b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁 

5.使用局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,
副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

ThreadLocal 类的常用方法
ThreadLocal() : 创建一个线程本地变量 
get() : 返回此线程局部变量的当前线程副本中的值 
initialValue() : 返回此线程局部变量的当前线程的"初始值" 
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
例如:   在上面例子基础上,修改后的代码为: 
//只改Bank类,其余代码与上同public class Bank{//使用ThreadLocal类管理共享变量accountprivate static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){@Overrideprotected Integer initialValue(){return 100;}};public void save(int money){account.set(account.get()+money);}public int getAccount(){return account.get();}}
注:ThreadLocal与同步机制 a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。 b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方式

6.使用阻塞队列实现线程同步

前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。 
使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。 
本小节主要是使用LinkedBlockingQueue<E>来实现线程的同步 
LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。 
队列是先进先出的顺序(FIFO),关于队列以后会详细讲解~ 

LinkedBlockingQueue 类常用方法
LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue
put(E e) : 在队尾添加一个元素,如果队列满则阻塞
size() : 返回队列中的元素个数
take() : 移除并返回队头元素,如果队列空则阻塞

代码实例:
实现商家生产商品和买卖商品的同步

 1 package com.xhj.thread;2 3 import java.util.Random;4 import java.util.concurrent.LinkedBlockingQueue;5 6 /**7  * 用阻塞队列实现线程同步 LinkedBlockingQueue的使用8  * 9  * @author XIEHEJUN
10  * 
11  */
12 public class BlockingSynchronizedThread {
13     /**
14      * 定义一个阻塞队列用来存储生产出来的商品
15      */
16     private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
17     /**
18      * 定义生产商品个数
19      */
20     private static final int size = 10;
21     /**
22      * 定义启动线程的标志,为0时,启动生产商品的线程;为1时,启动消费商品的线程
23      */
24     private int flag = 0;
25 
26     private class LinkBlockThread implements Runnable {
27         @Override
28         public void run() {
29             int new_flag = flag++;
30             System.out.println("启动线程 " + new_flag);
31             if (new_flag == 0) {
32                 for (int i = 0; i < size; i++) {
33                     int b = new Random().nextInt(255);
34                     System.out.println("生产商品:" + b + "号");
35                     try {
36                         queue.put(b);
37                     } catch (InterruptedException e) {
38                         // TODO Auto-generated catch block
39                         e.printStackTrace();
40                     }
41                     System.out.println("仓库中还有商品:" + queue.size() + "个");
42                     try {
43                         Thread.sleep(100);
44                     } catch (InterruptedException e) {
45                         // TODO Auto-generated catch block
46                         e.printStackTrace();
47                     }
48                 }
49             } else {
50                 for (int i = 0; i < size / 2; i++) {
51                     try {
52                         int n = queue.take();
53                         System.out.println("消费者买去了" + n + "号商品");
54                     } catch (InterruptedException e) {
55                         // TODO Auto-generated catch block
56                         e.printStackTrace();
57                     }
58                     System.out.println("仓库中还有商品:" + queue.size() + "个");
59                     try {
60                         Thread.sleep(100);
61                     } catch (Exception e) {
62                         // TODO: handle exception
63                     }
64                 }
65             }
66         }
67     }
68 
69     public static void main(String[] args) {
70         BlockingSynchronizedThread bst = new BlockingSynchronizedThread();
71         LinkBlockThread lbt = bst.new LinkBlockThread();
72         Thread thread1 = new Thread(lbt);
73         Thread thread2 = new Thread(lbt);
74         thread1.start();
75         thread2.start();
76 
77     }
78 
79 }

注:BlockingQueue定义了阻塞队列的常用方法,尤其是三种添加元素的方法,我们要多加注意,当队列满时:
  add()方法会抛出异常

offer()方法返回false

put()方法会阻塞

7.使用原子变量实现线程同步

需要使用线程同步的根本原因在于对普通变量的操作不是原子的。

那么什么是原子操作呢?
原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作
即-这几种行为要么同时完成,要么都不完成。

在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,
使用该类可以简化线程同步。

其中AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),
但不能用于替换Integer;可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。

AtomicInteger类常用方法:
AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger
addAddGet(int dalta) : 以原子方式将给定值与当前值相加
get() : 获取当前值

代码实例:
只改Bank类,其余代码与上面第一个例子同

 1 class Bank {2         private AtomicInteger account = new AtomicInteger(100);3 4         public AtomicInteger getAccount() {5             return account;6         }7 8         public void save(int money) {9             account.addAndGet(money);
10         }
11     } 

参考文章: Java多线程学习(一)- Java线程的生命周期与创建方式
详解synchronized与Lock的区别与使用


http://chatgpt.dhexx.cn/article/DJWIkl0T.shtml

相关文章

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 …

Microsoft Excel 教程:如何在 Excel 中使用 COUNTIF 函数?

欢迎观看 Microsoft Excel 教程&#xff0c;小编带大家学习 Microsoft Excel 的使用技巧&#xff0c;了解如何在 Excel 中使用 COUNTIF 函数。 COUNTIF 是一个统计函数&#xff0c;用于统计满足某个条件的单元格的数量&#xff1b;例如&#xff0c;某个姓名在单元格区域中出现…

[Excel函数] COUNT函数 | COUNTIF函数 | COUNTIFS函数

1.COUNT函数 语法: COUNT(value1,[value2],...) COUNT函数用于计算区域中包含数字的单元格的个数 (不统计文本性数字) COUNT函数很少单独使用&#xff0c;一般和其他函数嵌套使用 案例: 统计数字的个数 注意: A13该单元格数字为文本格式&#xff0c;COUNT函数不统计文本性数字 …

Excel如何使用COUNTIF函数

COUNTIF函数是我们在工作中经常使用的函数&#xff0c;今天就给大家分享一下如何使用countif函数。 1、COUNTIF函数主要用于对区域中满足单个指定条件的单元格进行计数。它的语法结构是COUNTIF(统计区域&#xff0c;统计条件) 注意要点 1.COUNTIF不区分大小写。 2.在条件中可…

sum与countif、countifs函数套用

1、sum与countif套用&#xff0c;实现多条件计数求和 公式&#xff1a;sum(countif(条件区域,{"条件1","条件2","条件3"})) 示例&#xff1a; 2、sum与countifs套用&#xff0c;实现多区域多条件计数求和 公式&#xff1a;sum(countifs(条件区…

COUNTIFS函数使用

COUNTIFS函数是Excel中的一个统计函数&#xff0c;用来计算多个区域中满足给定条件的单元格的个数&#xff0c;可以同时设定多个条件。 countifs(criteria_range1,criteria1,criteria_range2,criteria2,…) 参数说明 criteria_range1&#xff1a;为第一个需要计算其中满足某个…

excel 第9讲:countif函数

一、使用Countif函数 1 、Count函数 2、Countif函教语法&#xff1a;countif(range,criteria) 3 、Countif函数计算数值区间 4 、countif函教超过15位字符时的错误 二、常见应用示例 1、在数据区域中寻找重复数据 2、在数据有效性中使用countif函数 3、在条件格式中使用…

COUNTIF函数的使用方法

今天给大家介绍一下countif函数的使用方法&#xff0c;以及实例演示一下如何使用countif函数统计不重复值个数、按部门添加序号、统计不同区间工资人数。 COUNTIF函数主要用于对区域中满足单个指定条件的单元格进行计数。它的语法结构是COUNTIF(统计区域&#xff0c;统计条件)…

countif函数怎么用?countif函数的使用方法

countif函数怎么用&#xff1f;你学会了countif函数的使用方法了吗&#xff1f;countif函数是对指定区域中符合指定条件的单元格计数的一个函数&#xff0c;如果需要计算个数的话&#xff0c;这个函数绝对好用&#xff01;而且操作也简单&#xff0c;一起来学习一下吧&#xff…

countif函数

COUNTIF函数 COUNTIF 是一个统计函数&#xff0c;用于统计满足某个条件的单元格的数量。 COUNTIF(选择区域&#xff0c;要查找的内容&#xff09;COUNTIF(A2:A5,“London”)COUNTIF(A2:A5,A4) 选择区域&#xff1a;该参数指定查找和计数的单元格范围 要查找的内容&#xff1…