Java并发编程:线程间通讯与进程间通讯

101 阅读2分钟

在Java中,线程和进程之间的通信方式有所不同。以下是线程和进程之间通信的常见方法:

1. 线程之间的通信

线程之间可以通过以下几种方式进行通信:

1.1 共享变量

线程可以通过共享对象的字段或变量进行通信。为了确保线程安全,通常需要使用同步机制(如synchronized关键字或java.util.concurrent包中的工具类)。

class SharedObject {
    private int value;
    private boolean available = false;

    public synchronized int get() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        available = false;
        notifyAll();
        return value;
    }

    public synchronized void put(int value) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        this.value = value;
        available = true;
        notifyAll();
    }
}

1.2 使用wait()notify()notifyAll()

这些方法用于线程之间的协调。wait()使当前线程等待,直到另一个线程调用notify()notifyAll()来唤醒它。

1.3 使用BlockingQueue

java.util.concurrent.BlockingQueue是一个线程安全的队列,支持阻塞操作。生产者线程可以将数据放入队列,消费者线程可以从队列中取出数据。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ProducerConsumer {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);

        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    queue.put(i);
                    System.out.println("Produced: " + i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread consumer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    int value = queue.take();
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

2. 进程之间的通信

进程之间的通信(IPC, Inter-Process Communication)可以通过以下几种方式实现:

2.1 使用Socket

进程可以通过网络套接字进行通信,即使它们运行在不同的机器上。

// Server
import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(12345);
        Socket socket = serverSocket.accept();
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = in.readLine();
        System.out.println("Received: " + message);
        socket.close();
        serverSocket.close();
    }
}

// Client
import java.io.*;
import java.net.*;

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

2.2 使用PipedInputStreamPipedOutputStream

PipedInputStreamPipedOutputStream可以用于同一个JVM中的两个进程之间的通信。

import java.io.*;

public class PipedExample {
    public static void main(String[] args) throws IOException {
        final PipedOutputStream output = new PipedOutputStream();
        final PipedInputStream input = new PipedInputStream(output);

        Thread writer = new Thread(() -> {
            try {
                output.write("Hello, Reader!".getBytes());
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        Thread reader = new Thread(() -> {
            try {
                int data;
                while ((data = input.read()) != -1) {
                    System.out.print((char) data);
                }
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        writer.start();
        reader.start();
    }
}

2.3 使用RMI(远程方法调用)

Java RMI允许一个JVM中的对象调用另一个JVM中的对象的方法。

2.4 使用Java NIOFileChannel

进程可以通过文件进行通信,使用FileChannel来读写文件。

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelExample {
    public static void main(String[] args) throws IOException {
        RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
        FileChannel channel = file.getChannel();

        // Write to file
        ByteBuffer buffer = ByteBuffer.allocate(48);
        buffer.clear();
        buffer.put("Hello, FileChannel!".getBytes());
        buffer.flip();
        while (buffer.hasRemaining()) {
            channel.write(buffer);
        }

        // Read from file
        buffer.clear();
        channel.read(buffer);
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }

        channel.close();
        file.close();
    }
}

总结

  • 线程通信:可以通过共享变量、wait()/notify()BlockingQueue等方式进行。
  • 进程通信:可以通过SocketPipedInputStream/PipedOutputStreamRMIFileChannel等方式进行。

选择哪种通信方式取决于具体的应用场景和需求。