进程同步和线程的同步

进程间同步

1. 概念

进程是程序在操作系统中的一次执行过程,每个进程都有自己独立的内存空间和系统资源。进程间同步是指多个进程在访问共享资源或进行协作时,按照一定规则协调执行顺序,以保证数据一致性和程序正确性。

2. 同步原因

多个进程可能同时访问和修改共享资源,如共享文件、共享内存区域等,这会导致竞争条件和数据不一致问题。例如,多个进程同时对一个共享文件进行写操作,可能会导致文件内容混乱。

3. 同步方法
  • 信号量(Semaphore)
    • 原理:信号量是一个计数器,用于控制对共享资源的访问。进程可以通过 P 操作(申请资源,计数器减 1)和 V 操作(释放资源,计数器加 1)来获取和释放资源。当计数器小于 0 时,进程会被阻塞。
    • Java 示例:在 Java 中没有直接的信号量用于进程间同步,但可以借助操作系统的机制或第三方库。在 Linux 下可以使用 JNI(Java Native Interface)调用系统的信号量函数。以下是一个简单示意:
// 假设使用 JNI 调用系统信号量函数
public class SemaphoreProcessSync {
    static {
        System.loadLibrary("semaphore_jni");
    }

    // 声明本地方法
    public native void semaphoreP();
    public native void semaphoreV();

    public static void main(String[] args) {
        SemaphoreProcessSync sync = new SemaphoreProcessSync();
        // 模拟进程操作
        sync.semaphoreP();
        try {
            // 临界区代码
            System.out.println("Process is in critical section.");
        } finally {
            sync.semaphoreV();
        }
    }
}
  • 消息队列(Message Queue)
    • 原理:消息队列是一种在进程之间传递消息的机制。进程可以将消息发送到队列中,也可以从队列中接收消息,实现进程间的异步通信。
    • Java 示例:可以使用 Java 的 java.net 包通过网络实现类似消息队列的功能,以下是一个简单的基于 TCP 套接字的消息传递示例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

// 服务器端进程
class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(12345)) {
            System.out.println("Server is listening on port 12345");
            Socket socket = serverSocket.accept();
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message = in.readLine();
            System.out.println("Received message: " + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 客户端进程
class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 12345);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
            out.println("Hello from client!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 共享内存(Shared Memory)
    • 原理:多个进程可以访问同一块物理内存区域,从而实现数据的共享。进程可以直接在共享内存中读写数据,提高数据传输效率。
    • Java 示例:Java 中可以通过 java.nio 包的 MappedByteBuffer 实现文件映射到内存,模拟共享内存。以下是一个简单示例:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class SharedMemoryExample {
    public static void main(String[] args) {
        try (RandomAccessFile file = new RandomAccessFile("shared_memory.txt", "rw");
             FileChannel channel = file.getChannel()) {
            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
            // 写入数据
            buffer.put("Hello, shared memory!".getBytes());
            // 读取数据
            buffer.flip();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            System.out.println(new String(data));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程间同步

1. 概念

线程是进程内的执行单元,同一进程内的多个线程共享进程的资源。线程间同步是指在一个进程内,多个线程在访问共享资源或进行协作时,采取措施协调执行顺序,避免数据竞争和不一致问题。

2. 同步原因

多个线程同时访问和修改共享资源时,会导致数据不一致和竞争条件。例如,多个线程同时对一个共享变量进行自增操作,可能会导致最终结果不符合预期。

3. 同步方法
  • synchronized 关键字
    • 原理synchronized 关键字可以修饰方法或代码块,当一个线程访问被 synchronized 修饰的代码时,会自动获取对象的锁,其他线程必须等待该线程释放锁才能访问。
    • Java 示例
class Counter {
    private int count = 0;

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

    public int getCount() {
        return count;
    }
}

public class SynchronizedExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

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

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

        System.out.println("Final count: " + counter.getCount());
    }
}
  • ReentrantLock
    • 原理ReentrantLock 是 Java 提供的可重入锁,功能比 synchronized 更强大,提供了更多的方法来控制锁的获取和释放。
    • Java 示例
import java.util.concurrent.locks.ReentrantLock;

class CounterWithLock {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();

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

    public int getCount() {
        return count;
    }
}

public class ReentrantLockExample {
    public static void main(String[] args) throws InterruptedException {
        CounterWithLock counter = new CounterWithLock();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

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

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

        System.out.println("Final count: " + counter.getCount());
    }
}
  • Semaphore
    • 原理Semaphore 用于控制同时访问某个资源的线程数量。线程可以通过 acquire() 方法获取许可,通过 release() 方法释放许可。
    • Java 示例
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 允许同时访问的线程数为 2

        Runnable task = () -> {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " acquired the semaphore.");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release();
                System.out.println(Thread.currentThread().getName() + " released the semaphore.");
            }
        };

        for (int i = 0; i < 5; i++) {
            new Thread(task).start();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值