Java转C之并发和多线程

发布于:2024-12-18 ⋅ 阅读:(96) ⋅ 点赞:(0)

提纲:

  1. 概念介绍与对比概述
    • 简述Java与C在并发和多线程方面的核心区别
    • 解释C11标准、POSIX、C11 <threads.h>、Pthread等名词
  2. Java多线程与并发回顾
    • 线程、Runnable、ExecutorService概念说明
    • 同步关键字与工具类含义
  3. C并发基础
    • 没有Java式的内置线程类,需要外部库或标准扩展
    • C11标准和<threads.h>介绍
    • POSIX Pthreads介绍
    • 同步机制(互斥锁、条件变量)简单解释
  4. 场景与示例对比
    • Java线程池与C中的手动实现线程池
    • 全面示例从简单到复杂
  5. 最佳实践总结

概念介绍与对比概述

并发多线程是指让程序同时(或者看起来同时)做多件事的能力。在Java中,这很容易实现:你可以创建线程对象并启动,使用内置的类和方法让多个任务并行执行。而在C中,你需要了解一些额外的概念和库,因为C语言本身最初并没有把多线程放入标准中。

C11 标准是什么?

C语言有不同的标准版本,由国际标准化组织制定。C11(读作"See eleven")是2011年发布的C语言标准版本。在C11中,首次引入了一些基本的多线程支持的头文件 <threads.h>,提供了创建和管理线程的基础功能,但功能比较有限,远不如Java丰富。

POSIX 是什么?

POSIX(Portable Operating System Interface)是一个操作系统接口标准,定义了一套在不同系统上通用的API和特性。其中包括线程(称为Pthreads,也就是POSIX Threads)相关的API。POSIX是个标准,Unix、Linux和macOS等系统遵循POSIX标准,可使用相同的线程函数。

简单来说:

  • POSIX是一个标准,规定了一些函数和行为,让程序在多个系统上都能以相似方式运行。
  • Pthreads是POSIX标准中定义的一组用于多线程的API函数。

<threads.h> 是什么?

<threads.h> 是C11标准引入的头文件,提供了创建、加入(thread join)线程的函数,还有互斥锁等基本同步机制。它是C标准的一部分,但实现程度在不同编译器和系统上可能不完全一致。此外,它比POSIX线程API更简单和功能较少。

pthread(Pthreads)是什么?

Pthread是POSIX Threads的简称,是在POSIX标准中定义的一套多线程API。不属于C标准本身,是操作系统提供的库,但在类Unix系统(Linux/macOS)上很常用。相比C11 <threads.h>,Pthreads功能更强大、使用更广泛。


Java多线程与并发回顾

在Java中,多线程功能是内置的:

  • 使用Thread类或Runnable接口创建线程。
  • 使用synchronized关键字保证线程安全访问共享数据。
  • volatile关键字保证变量对所有线程可见。
  • 高级框架:ExecutorServiceForkJoinPoolCompletableFutureConcurrentHashMap等工具类,使并发编程更简单。

Java简单示例

class MyTask implements Runnable {
    public void run() {
        System.out.println("Running in " + Thread.currentThread().getName());
    }
}

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new MyTask());
        t.start(); // 启动线程
    }
}

这里Java很容易就创建并运行一个新线程。


C并发基础

C最初设计时没有多线程概念。多线程特性是后来才通过标准扩展和第三方库加入的。

C11 <threads.h> 简单说明

C11标准给C语言增加了一个基础的多线程支持头文件 <threads.h>,其中有:

  • thrd_create() 创建线程
  • thrd_join() 等待线程结束
  • 互斥锁 mtx_t 用于保护共享数据
  • 原子操作和简单的同步工具

然而,这套API功能有限,不如Java丰富,也不如POSIX pthreads常用。

POSIX Pthreads

在Unix/Linux/macOS系统上,常用POSIX线程库(pthreads)来实现多线程,包括:

  • pthread_create() 创建线程
  • pthread_join() 等待线程结束
  • pthread_mutex_t互斥锁、pthread_cond_t条件变量实现复杂同步

Pthreads是非常常见的C多线程方式,相对于C11 <threads.h>来说功能更丰富。在Windows平台有自己的多线程API(Win32 Threads)。


同步机制介绍

在多线程中,如果多个线程同时访问和修改共享变量,可能会出错,需要同步。

  • 互斥锁(mutex):一次只允许一个线程进入某个代码区,类似Java中的synchronized锁。
  • 条件变量(condition variable):让线程等待特定条件(如队列不空),当条件满足时通知等待线程继续执行。

Java中有高级数据结构和锁,而C中则需手动使用pthread_mutex_lock()pthread_mutex_unlock()来锁定和解锁资源。


场景与示例对比

Java线程池场景

在Java中,你可能有10个任务要处理,这些任务可以并行执行。你只需使用ExecutorService创建一个固定大小的线程池,然后submit()任务:

import java.util.concurrent.*;

public class JavaThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4); // 创建4线程的池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Java Task " + taskId + " by " + Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}

这样Java自动管理线程、队列和任务调度,不需要你手动处理同步队列等细节。

C中实现类似线程池

C中没有内置线程池,需要手动:

  • 使用Pthreads创建多个工作线程
  • 使用队列存放任务,队列需要锁和条件变量
  • 线程等待队列有任务后获取并执行

示例思路(简化):

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

#define MAX_TASKS 100
typedef struct {
    void (*func)(void*);
    void *arg;
} Task;

Task tasks[MAX_TASKS];
int task_count = 0;
int stop = 0;

pthread_mutex_t task_lock;
pthread_cond_t task_cond;

void add_task(void (*func)(void*), void *arg) {
    pthread_mutex_lock(&task_lock);
    if (task_count < MAX_TASKS) {
        tasks[task_count].func = func;
        tasks[task_count].arg = arg;
        task_count++;
        pthread_cond_signal(&task_cond);
    }
    pthread_mutex_unlock(&task_lock);
}

void* worker(void* arg) {
    while (1) {
        pthread_mutex_lock(&task_lock);
        while (task_count == 0 && !stop) {
            pthread_cond_wait(&task_cond, &task_lock);
        }
        if (stop && task_count == 0) {
            pthread_mutex_unlock(&task_lock);
            break;
        }
        Task task = tasks[--task_count];
        pthread_mutex_unlock(&task_lock);

        // 执行任务
        task.func(task.arg);
    }
    return NULL;
}

void print_msg(void *arg) {
    char* msg = (char*)arg;
    printf("C Thread %ld: %s\n", pthread_self(), msg);
    free(msg);
}

int main() {
    pthread_mutex_init(&task_lock, NULL);
    pthread_cond_init(&task_cond, NULL);

    pthread_t threads[4];
    for (int i = 0; i < 4; i++) {
        pthread_create(&threads[i], NULL, worker, NULL);
    }

    for (int i = 0; i < 10; i++) {
        char *msg = (char*)malloc(50);
        sprintf(msg, "Task %d", i);
        add_task(print_msg, msg);
    }

    sleep(1); // 等待任务执行一会儿
    pthread_mutex_lock(&task_lock);
    stop = 1;
    pthread_cond_broadcast(&task_cond);
    pthread_mutex_unlock(&task_lock);

    for (int i = 0; i < 4; i++) {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&task_lock);
    pthread_cond_destroy(&task_cond);

    return 0;
}

这个C程序实现了一个简易的"线程池":

  • 使用pthread_create()启动4个工作线程。
  • 当添加任务时,用锁保护队列并signal条件变量。
  • 工作线程被条件变量唤醒后从队列中取出任务执行。

比起Java的一行Executors.newFixedThreadPool(4)简单声明,这在C中要写许多代码手动控制。


对比表格

特性 Java C
内置并发支持 有,ThreadRunnableExecutorService 无强制要求的内建库,C11有基础<threads.h>但简化版
线程创建 new Thread(...)+start()Executor框架 pthread_create()(POSIX) 或 thrd_create()(C11)
同步方式 synchronizedLockvolatile、高级工具类 pthread_mutex_t互斥锁、pthread_cond_t条件变量
高级并发工具 丰富:ExecutorService、并发集合、CompletableFuture 需自行实现,没有内置高级并发容器
内存模型 明确的Java内存模型保证线程通信语义 C标准中直到C11才有简单原子操作,无完整高级内存模型
学习与使用难度 易学易用、类库丰富、工具多 难度高,需手动实现许多逻辑

最佳实践与总结

  • 对于Java

    • 优先使用ExecutorServiceBlockingQueue等高级API。
    • 使用synchronizedLock保证线程安全访问共享数据。
    • 利用Java内置内存模型和工具类减少错误。
  • 对于C

    • 使用POSIX线程(pthread)在类Unix系统实现多线程;在C11中可尝试<threads.h>但特性较弱。
    • 手动使用互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)实现同步。
    • 无内置高级数据结构,需要自制线程安全队列、线程池。
    • 更细致但更繁琐的内存和资源管理,避免内存泄漏和死锁。

总结
在Java中,多线程和并发通过丰富的语言和库特性简单实现;而在C中,需要更多底层知识和手动管理来达到相似的效果。C的并发编程灵活但复杂,开发者需更谨慎和投入更多努力来确保程序高效、安全和可维护。


网站公告

今日签到

点亮在社区的每一天
去签到