杰瑞科技汇

Linux下Java如何获取CPU序列号?

CPU 序列号是什么?

我们需要明确一个非常重要的概念:现代 CPU 并没有一个像硬盘序列号那样全球唯一的、固化的“序列号”

Linux下Java如何获取CPU序列号?-图1
(图片来源网络,侵删)

我们通常所说的“CPU 序列号”其实是指 CPU 的一个全局唯一标识符,这个 ID 主要来源于 CPU 的 UUID (Universally Unique Identifier),这个 UUID 是在 CPU 制造时被写入到一个特殊寄存器中的,理论上保证全球唯一。

对于 x86 架构的 CPU(Intel, AMD),这个信息可以通过读取 /proc/cpuinfo 文件中的 cpuid 字段来获取,这个 cpuid 值就是 CPU 的 UUID。


通过读取 /proc/cpuinfo (最常用、最可靠)

这是在 Linux 系统上获取 CPU 信息最标准、最可靠的方法。/proc/cpuinfo 是一个虚拟文件系统,它包含了 CPU 的详细信息。

步骤 1:在 Shell 中查看 CPU 信息

打开终端,执行以下命令:

Linux下Java如何获取CPU序列号?-图2
(图片来源网络,侵删)
cat /proc/cpuinfo

你会看到类似下面的输出(以一个 Intel CPU 为例):

processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 79
model name  : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
stepping    : 3
microcode   : 0xba
cpu MHz     : 2095.438
cache size  : 8192 KB
physical id : 0
siblings    : 8
core id     : 0
cpu cores   : 4
apicid      : 0
initial apicid  : 0
fpu     : yes
fpu_exception   : yes
cpuid level : 22
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm mpx avx512f avx512dq rdseed adx smap clflushopt clwb intel_pt avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities
bugs        : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit srbds mmio_stale_data retbleed
bogomips    : 4390.40
clflush size    : 64
cache_alignment : 64
address sizes   : 39 bits physical, 48 bits virtual
power management:

注意:如果你有多个 CPU 核心,这个文件会包含所有核心的信息,每个核心的信息块之间会有一个空行,我们需要从其中任意一个核心的信息块里提取 cpuid

步骤 2:在 Java 中实现

Java 代码的核心思路是:

  1. 使用 Runtime.exec()ProcessBuilder 执行 cat /proc/cpuinfo 命令。
  2. 读取命令的输出流。
  3. 解析输出流的内容,找到 cpuid 这一行的值。
  4. 关闭所有流以避免资源泄漏。

下面是完整的 Java 代码示例:

Linux下Java如何获取CPU序列号?-图3
(图片来源网络,侵删)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class CpuSerialReader {
    public static void main(String[] args) {
        try {
            // 调用系统命令读取 /proc/cpuinfo
            Process process = Runtime.getRuntime().exec("cat /proc/cpuinfo");
            // 使用 BufferedReader 读取命令的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            // 逐行读取
            while ((line = reader.readLine()) != null) {
                // 查找包含 "cpuid" 的行
                if (line.contains("cpuid")) {
                    // cpuid 的格式通常是 "cpuid : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
                    String[] parts = line.split(":");
                    if (parts.length == 2) {
                        String cpuId = parts[1].trim();
                        System.out.println("CPU ID (UUID): " + cpuId);
                    }
                    break; // 找到后就可以退出了
                }
            }
            // 等待命令执行完毕,并检查返回码
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                System.err.println("Command execution failed with exit code: " + exitCode);
            }
            reader.close();
            process.destroy();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

代码解释:

  • Runtime.getRuntime().exec("cat /proc/cpuinfo"): 启动一个新进程来执行 cat 命令。
  • process.getInputStream(): 获取这个进程的标准输出流,也就是 cat 命令打印到控制台的内容。
  • BufferedReader: 高效地读取流中的内容。
  • line.contains("cpuid"): 判断当前行是否包含我们需要的标识。
  • line.split(":"): 用冒号分割字符串,得到键和值。
  • parts[1].trim(): 获取冒号后面的部分,并去除首尾空格。
  • process.waitFor(): 阻塞当前线程,直到外部进程执行完毕,这是一个好习惯,可以避免僵尸进程。

使用 dmidecode 命令 (需要 root 权限)

dmidecode 是一个可以读取计算机 DMI (SMBIOS) 表信息的工具,这个表包含了硬件的详细信息,其中也包括处理器的序列号,这个命令通常需要 root 权限才能执行。

步骤 1:在 Shell 中查看

# 需要 sudo 权限
sudo dmidecode -t processor

输出会类似这样:

# dmidecode 3.2
Getting SMBIOS data from sysfs.
SMBIOS 3.0.0 present.
Handle 0x0004, DMI type 4, 52 bytes
Processor Information
        Socket Designation: CPU 1
        Type: Central Processor
        Family: Core i7
        Manufacturer: Intel
        ID: BFEBFBFF000906EA  <-- 这就是 CPU ID
        Signature: Type 0, Family 6, Model 79, Stepping 3
        Version: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
        Voltage: 1.3 V
        External Clock: 100 MHz
        Max Speed: 4000 MHz
        Current Speed: 2100 MHz
        Status: Populated, Enabled
        Upgrade: None
        L1 Cache Handle: 0x0005
        L2 Cache Handle: 0x0006
        L3 Cache Handle: 0x0007
        Serial Number: To Be Filled By O.E.M.  <-- 通常这里是空的
        Asset Tag: To Be Filled By O.E.M.
        Part Number: To Be Filled By O.E.M.
        Core Count: 4
        Core Enabled: 4
        Thread Count: 8
        Characteristics: 64-bit capable, Multi-Core, HTT, ECC

这里的 ID 字段 BFEBFBFF000906EA CPU 的 ID。

步骤 2:在 Java 中实现

Java 代码逻辑与第一种方法类似,只是执行的命令和解析的行不同。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class DmidecodeCpuReader {
    public static void main(String[] args) {
        try {
            // 注意:需要 root 权限,所以最好用 sudo 来运行 Java 程序
            //  sudo java DmidecodeCpuReader
            Process process = Runtime.getRuntime().exec("dmidecode -t processor");
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                // 查找包含 "ID:" 的行
                if (line.trim().startsWith("ID:")) {
                    // 格式 "ID: BFEBFBFF000906EA"
                    String cpuId = line.split(":", 2)[1].trim();
                    System.out.println("CPU ID (from dmidecode): " + cpuId);
                    break;
                }
            }
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                System.err.println("Command execution failed. Make sure dmidecode is installed and you have sudo privileges.");
                System.err.println("Exit code: " + exitCode);
            }
            reader.close();
            process.destroy();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

重要注意事项和最佳实践

  1. 权限问题

    • 方法一 (/proc/cpuinfo) 任何普通用户都有读取权限,是首选。
    • 方法二 (dmidecode) 需要 root 权限,在生产环境中使用会增加安全风险,并且可能因为权限问题失败。
  2. 跨平台问题

    • 这两种方法都仅适用于 Linux 系统,如果你的 Java 程序需要跨平台运行(Windows, macOS),你需要为不同操作系统编写不同的逻辑。
    • 在 Windows 上,可以通过 wmic cpu get ProcessorId 或读取注册表。
    • 在 macOS 上,可以通过 system_profiler SPHardwareDataType | grep "Processor Name"ioreg -l 来获取。
  3. 虚拟化环境

    • 在虚拟机(VMware, VirtualBox, KVM 等)中,/proc/cpuinfodmidecode 返回的可能是虚拟宿主机的信息,而不是物理机的,如果你想获取物理机的信息,需要宿主机提供特殊的机制(VMware 的 vmware-toolbox-cmd)。
  4. 健壮性

    • 总是要检查命令的返回值 (process.waitFor()),如果命令执行失败(dmidecode 未安装),程序可以做出相应处理,而不是直接崩溃。
    • 使用 try-with-resources 语句可以更优雅地管理流资源,避免忘记关闭 InputStreamReaderBufferedReader
    // 使用 try-with-resources 的改进版
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
        // ... 读取逻辑 ...
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
方法 优点 缺点 推荐度
读取 /proc/cpuinfo 无需 root 权限,简单可靠,是 Linux 标准做法 仅限 Linux ⭐⭐⭐⭐⭐
使用 dmidecode 信息更丰富(可能包含其他硬件ID) 需要 root 权限,有安全风险,可能失败 ⭐⭐

对于在 Linux 环境下使用 Java 获取 CPU 序列号,强烈推荐使用第一种方法,即读取 /proc/cpuinfo 文件,它是最稳定、最安全、也是最符合 Linux 设计哲学的方式。

分享:
扫描分享到社交APP
上一篇
下一篇