在 Java 中,线程同步和通信是多线程编程的重要部分,用于确保多个线程安全地访问共享资源以及协调它们之间的执行顺序。以下是实现线程同步和通信的常见方法和机制:

线程同步

1. synchronized 关键字

synchronized 关键字可以用于修饰方法或代码块,确保同一时间只有一个线程可以访问被修饰的方法或代码块,从而实现线程同步。

  • 同步方法
class Counter {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }
}
  • 同步代码块
class Counter {
    private int count = 0;
    private final Object lock = new Object();

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

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

2. ReentrantLock

ReentrantLock 是 Java 并发包中的一个可重入锁,它提供了比 synchronized 更灵活的锁定机制。

import java.util.concurrent.locks.ReentrantLock;

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

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

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

线程通信

1. wait()notify()notifyAll() 方法

这三个方法是 Object 类的方法,用于线程间的等待和唤醒操作。

class Message {
    private String content;
    private boolean available = false;

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

    public synchronized String take() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        available = false;
        notifyAll();
        return content;
    }
}

2. Condition 接口

Condition 接口是 ReentrantLock 的配套工具,用于实现线程间的精细通信。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Message {
    private String content;
    private boolean available = false;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public void put(String content) {
        lock.lock();
        try {
            while (available) {
                notFull.await();
            }
            this.content = content;
            available = true;
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public String take() {
        lock.lock();
        try {
            while (!available) {
                notEmpty.await();
            }
            available = false;
            notFull.signalAll();
            return content;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
        return null;
    }
}

3. BlockingQueue 接口

BlockingQueue 是 Java 并发包中的一个阻塞队列,它提供了线程安全的入队和出队操作,并且在队列为空或已满时会自动阻塞线程。

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

class ProducerConsumerExample {
    private static final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    queue.put(i);
                    System.out.println("Produced: " + i);
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

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

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

这些方法和机制可以根据具体的需求选择使用,以实现线程的同步和通信。