好的!下面帮你详细总结线程通信进程通信的区别,包含概念、方式、特点和应用场景,方便理解和区分。


线程通信与进程通信的区别

比较维度线程通信进程通信
通信主体同一进程内的多个线程不同进程之间
内存空间共享进程的内存空间各自独立的内存空间
通信方式通过共享内存、同步机制(如锁、条件变量、信号量)需要专门的通信机制,如管道、消息队列、共享内存、信号、Socket等
通信开销较小,线程间切换成本低较大,进程切换开销高,通信成本高
实现复杂度需关注同步与互斥,防止数据竞争通信机制更复杂,涉及内核中介
数据传输速度快,因共享内存相对慢,因需要内核参与和数据拷贝
安全性较低,同一进程内线程容易产生竞争较高,内存空间隔离,防止非法访问
应用场景需要频繁共享数据和协作的多线程程序不同应用间通信、分布式系统

具体通信方式举例

线程通信常用机制进程通信常用机制
互斥锁(Mutex)管道(pipe)
信号量(Semaphore)命名管道(Named pipe/FIFO)
条件变量(Condition Variable)消息队列(Message Queue)
读写锁(Read-Write Lock)共享内存(Shared Memory)
自旋锁(Spinlock)信号(Signal)
套接字(Socket)

简单总结

  • 线程通信:线程共享进程内存,通信高效但需同步机制保证数据安全。
  • 进程通信:进程间内存独立,需要通过操作系统提供的通信手段交换数据,安全性高但性能开销大。

好的!下面我给你详细讲解几种常见的进程通信(IPC)方式和线程通信同步机制的实现示例,包含C语言代码示范,帮你更好理解和掌握。


一、常见进程通信方式及示例(C语言)


1. 管道(Pipe)

  • 特征:半双工,父子进程间通信,内存共享有限。
  • 示例
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main() {
    int fd[2];
    pipe(fd);
    pid_t pid = fork();

    if (pid == 0) { // 子进程
        close(fd[1]); // 关闭写端
        char buf[100];
        read(fd[0], buf, sizeof(buf));
        printf("Child read: %s\n", buf);
        close(fd[0]);
    } else { // 父进程
        close(fd[0]); // 关闭读端
        const char *msg = "Hello from parent";
        write(fd[1], msg, strlen(msg)+1);
        close(fd[1]);
    }

    return 0;
}

2. 共享内存(Shared Memory)

  • 特征:最快的IPC方式,多个进程映射同一块物理内存。
  • 示例
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>

int main() {
    key_t key = 1234;
    int shmid = shmget(key, 1024, IPC_CREAT | 0666);
    char *data = (char *)shmat(shmid, NULL, 0);

    pid_t pid = fork();
    if (pid == 0) { // 子进程
        sleep(1); // 等待父进程写入
        printf("Child read from shm: %s\n", data);
        shmdt(data);
    } else { // 父进程
        strcpy(data, "Hello Shared Memory");
        shmdt(data);
        wait(NULL);
        shmctl(shmid, IPC_RMID, NULL);
    }
    return 0;
}

3. 消息队列(Message Queue)

  • 特征:基于消息的异步通信。
  • 示例
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf {
    long mtype;
    char mtext[100];
};

int main() {
    key_t key = 5678;
    int msgid = msgget(key, IPC_CREAT | 0666);
    struct msgbuf msg;
    pid_t pid = fork();

    if (pid == 0) { // 子进程
        msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0);
        printf("Child received: %s\n", msg.mtext);
    } else { // 父进程
        msg.mtype = 1;
        strcpy(msg.mtext, "Message Queue IPC");
        msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0);
    }
    return 0;
}

二、线程通信同步机制示例(C语言 + POSIX 线程)


1. 互斥锁(Mutex)

  • 用于保护共享数据,防止同时访问造成竞态条件。
#include <stdio.h>
#include <pthread.h>

int counter = 0;
pthread_mutex_t mutex;

void* increment(void* arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&mutex);
        counter++;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_mutex_init(&mutex, NULL);

    pthread_create(&t1, NULL, increment, NULL);
    pthread_create(&t2, NULL, increment, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("Counter: %d\n", counter); // 期望 200000

    pthread_mutex_destroy(&mutex);
    return 0;
}

2. 条件变量(Condition Variable)

  • 用于线程间通知与等待。
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;

void* wait_thread(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!ready) {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("Thread notified!\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void* signal_thread(void* arg) {
    pthread_mutex_lock(&mutex);
    ready = 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, wait_thread, NULL);
    sleep(1); // 确保wait_thread先等待
    pthread_create(&t2, NULL, signal_thread, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

三、线程与进程切换性能对比

  • 线程切换开销小,同一进程内切换,只需切换栈、寄存器,内存空间共享。
  • 进程切换开销大,涉及虚拟内存映射切换、页表切换,性能相对低。
  • 因此多任务中,线程适合细粒度并发,进程适合隔离性强的任务。

明白!下面我帮你总结一下Java中常见的线程同步与进程通信相关实现示例,方便你理解Java层面如何处理这两种通信方式。


一、Java线程同步示例


1. 使用synchronized关键字

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = () -> {
            for (int i = 0; i < 100000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Final count: " + counter.getCount());  // 期望 200000
    }
}

2. 使用ReentrantLock

import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = () -> {
            for (int i = 0; i < 100000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Final count: " + counter.getCount());  // 期望 200000
    }
}

二、Java进程间通信示例

Java标准库没有直接的进程间通信(IPC)API,但常用以下方式:


1. 使用文件或内存映射文件(MappedByteBuffer)

  • 适合简单数据交换。
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class SharedMemoryExample {
    public static void main(String[] args) throws Exception {
        RandomAccessFile raf = new RandomAccessFile("shared.dat", "rw");
        FileChannel channel = raf.getChannel();

        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);

        // 进程1写数据
        buffer.put(0, (byte) 123);

        // 进程2可映射同一文件,读取buffer.get(0)

        channel.close();
        raf.close();
    }
}

2. 使用Socket网络通信

  • 适合跨机器、跨进程通信。
// 简单的Server端
import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8888);
        Socket client = server.accept();
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        System.out.println("Received: " + in.readLine());
        in.close();
        client.close();
        server.close();
    }
}
// 简单的Client端
import java.net.Socket;
import java.io.*;

public class Client {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 8888);
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println("Hello from Client");
        out.close();
        socket.close();
    }
}

3. 使用Java Native Interface (JNI)

  • 结合C语言共享内存或消息队列实现。

三、总结

方面Java线程通信Java进程通信
实现方式synchronizedLockwait/notifySocket、文件映射、JNI封装等
共享资源共享进程内存,变量、对象通过文件、网络等跨进程传递数据
典型应用多线程并发控制跨进程数据交换、分布式通信

好的!下面帮你详细讲解Java多线程同步的高级用法,包括CountDownLatch、Semaphore和CyclicBarrier的原理、作用及示例代码。


一、CountDownLatch(倒计时锁存器)

  • 作用:让一个或多个线程等待其他线程完成操作后再继续执行。
  • 典型应用:等待多个线程执行完毕后,主线程才继续。
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 3;
        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 1; i <= threadCount; i++) {
            int num = i;
            new Thread(() -> {
                System.out.println("线程 " + num + " 执行任务");
                try {
                    Thread.sleep(1000 * num); // 模拟工作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程 " + num + " 完成");
                latch.countDown(); // 计数器减1
            }).start();
        }

        System.out.println("等待所有线程完成...");
        latch.await(); // 阻塞等待
        System.out.println("所有线程完成,主线程继续");
    }
}

二、Semaphore(信号量)

  • 作用:控制同时访问某资源的线程数量,类似一个计数器。
  • 典型应用:限制资源访问数量,比如连接池并发访问。
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        int permits = 2; // 同时允许2个线程访问
        Semaphore semaphore = new Semaphore(permits);

        for (int i = 1; i <= 5; i++) {
            int num = i;
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 获取许可,许可数-1
                    System.out.println("线程 " + num + " 获得许可,开始工作");
                    Thread.sleep(2000); // 模拟工作
                    System.out.println("线程 " + num + " 释放许可");
                    semaphore.release(); // 释放许可,许可数+1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

三、CyclicBarrier(循环屏障)

  • 作用:让一组线程互相等待,直到所有线程都达到屏障点后再同时继续执行。
  • 典型应用:多线程分阶段执行,需要同步的场景。
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int parties = 3;
        CyclicBarrier barrier = new CyclicBarrier(parties, () -> {
            System.out.println("所有线程到达屏障,继续执行后续任务");
        });

        for (int i = 1; i <= parties; i++) {
            int num = i;
            new Thread(() -> {
                try {
                    System.out.println("线程 " + num + " 准备到达屏障");
                    Thread.sleep(1000 * num); // 模拟准备工作
                    System.out.println("线程 " + num + " 到达屏障,等待其他线程");
                    barrier.await(); // 等待所有线程
                    System.out.println("线程 " + num + " 继续执行");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

四、总结对比

作用特点应用场景
CountDownLatch等待一组线程完成一次性,计数器不可重置等待多个任务结束
Semaphore控制并发访问资源线程数许可可多次获取和释放限制资源并发访问(连接池等)
CyclicBarrier多线程互相等待,循环使用可重复使用,支持屏障动作多线程分阶段同步执行